Skip to content

feat: report provider errors to discord#1937

Open
steebchen wants to merge 4 commits intomainfrom
provider-discord-pr
Open

feat: report provider errors to discord#1937
steebchen wants to merge 4 commits intomainfrom
provider-discord-pr

Conversation

@steebchen
Copy link
Copy Markdown
Member

@steebchen steebchen commented Mar 30, 2026

This adds worker-side Discord notifications for provider error logs via PROVIDER_ERROR_DISCORD_URL. The worker now reports upstream and gateway failures, while continuing to exclude client errors. It also handles provider errors that are missing a unified finish reason by falling back to HTTP status classification and a generic Discord title. Tests cover upstream errors, gateway errors, client-error exclusion, and missing-finish-reason reporting.

Summary by CodeRabbit

  • New Features

    • Added Discord webhook notifications for provider errors (upstream, gateway, and server-side 5xx, plus cases with null reason and 5xx). Notifications include a concise embed, redact sensitive IDs/emails, truncate long fields, skip when webhook URL is blank/whitespace, send after processing completes, and handle timeouts/non-2xx responses with error logging.
  • Tests

    • Expanded coverage for webhook delivery, embed content and redaction, non-delivery for client-side errors or blank webhook, and additional error-case permutations.

Copilot AI review requested due to automatic review settings March 30, 2026 13:02
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 30, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a provider-error Discord notifier service, updates the worker to batch and dispatch notifications after DB commit, and expands tests to cover notify/no-notify Discord webhook scenarios and restore test globals/env.

Changes

Cohort / File(s) Summary
Discord Notification Service
apps/worker/src/services/provider-error-discord.ts
New module exporting ProviderErrorNotificationLog and notifyProviderError(). Builds sanitized/truncated Discord embed from log/error metadata, reads process.env.PROVIDER_ERROR_DISCORD_URL, posts JSON with AbortController timeout, throws on non-2xx, and logs failures including logId.
Worker Integration
apps/worker/src/worker.ts
Updates batchProcessLogs() to evaluate logs via shouldNotifyProviderError() (rules: hasError, not client_error; notify for gateway_error/upstream_error or when reason is null and error_details.statusCode >= 500), accumulate ProviderErrorNotificationLog entries, and dispatch notifyProviderError() calls after committing. Also moves other post-transaction work (e.g., low-balance alerts) to run after commit.
Tests / Env & Mock Cleanup
apps/worker/src/log-processing.spec.ts
Adds Vitest afterEach/vi restores and captures prior PROVIDER_ERROR_DISCORD_URL; stubs global fetch; adds parameterized tests asserting Discord POST and payload contents for upstream_error/gateway_error and null reason, plus tests asserting no-notify for blank webhook and client_error.

Sequence Diagram

sequenceDiagram
    participant Worker as Worker (batchProcessLogs)
    participant DB as Database
    participant Filter as Eligibility Checker
    participant Service as ProviderErrorService
    participant Discord as Discord Webhook

    Worker->>DB: fetch batch of logs
    DB-->>Worker: log rows

    loop per log
        Worker->>Filter: shouldNotifyProviderError(log)
        alt eligible
            Filter-->>Worker: true
            Worker->>Worker: accumulate ProviderErrorNotificationLog
        else not eligible
            Filter-->>Worker: false
        end
    end

    Worker->>DB: commit processed flags
    DB-->>Worker: commit complete

    loop per accumulated log
        Worker->>Service: notifyProviderError(log)
        Service->>Service: build embed (type, description, redactions, truncation)
        Service->>Discord: POST embed JSON (webhook URL, 5s timeout)
        alt 2xx
            Discord-->>Service: success
        else non-2xx / timeout / fetch error
            Discord-->>Service: error + body
            Service->>Service: catch and logger.error(logId, err)
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'feat: report provider errors to discord' accurately and concisely describes the primary change: adding Discord webhook notifications for provider errors in the worker service.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch provider-discord-pr

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: acd2480d33

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/worker/src/worker.ts Outdated
Comment on lines +143 to +146
const statusCode = logRow.error_details?.statusCode;
if (statusCode !== undefined) {
return statusCode >= 500;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Honor finish reason before status fallback

shouldNotifyProviderError currently returns based on statusCode whenever error_details exists, so any upstream_error/gateway_error logged with a 4xx status (for example 429 upstream rate limits or 401/403 gateway auth failures classified in apps/gateway/src/chat/tools/get-finish-reason-from-error.ts) is silently skipped. This causes the new Discord alerting path to miss real provider/gateway failures even though they already have a non-client unified finish reason.

Useful? React with 👍 / 👎.

Comment on lines +39 to +40
const url = process.env.PROVIDER_ERROR_DISCORD_URL?.trim();
return url ?? null;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Treat blank Discord webhook as disabled

getProviderErrorDiscordUrl trims the env var but returns an empty string instead of null, so notifyProviderError proceeds and calls fetch("") when PROVIDER_ERROR_DISCORD_URL is set but blank. In that configuration every notifiable log generates avoidable error noise and no notifications are delivered.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds worker-side Discord notifications for provider error logs, controlled via PROVIDER_ERROR_DISCORD_URL, so upstream/gateway failures can be surfaced operationally while excluding client errors.

Changes:

  • Add provider error notification logic to batchProcessLogs() and a shouldNotifyProviderError() filter.
  • Introduce provider-error-discord service to format and send Discord webhook embeds.
  • Add Vitest coverage for upstream/gateway reporting, client-error exclusion, and missing finish-reason scenarios.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
apps/worker/src/worker.ts Collects notifiable provider-error logs during batch processing and dispatches Discord notifications post-transaction.
apps/worker/src/services/provider-error-discord.ts New service to build Discord embeds and POST them to the configured webhook URL.
apps/worker/src/log-processing.spec.ts Adds unit tests validating Discord reporting behavior and exclusion rules.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/worker/src/worker.ts Outdated
}

const statusCode = logRow.error_details?.statusCode;
if (statusCode !== undefined) {
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldNotifyProviderError returns early based on statusCode and only notifies for >= 500. In the gateway, upstream fetch/connection failures are logged with errorDetails.statusCode = 0 but unified_finish_reason = upstream_error (see apps/gateway/src/chat/chat.ts:6728+). With the current logic those upstream errors will never be reported to Discord. Consider treating statusCode === 0 (or generally non-HTTP / <100) as notifiable when unified_finish_reason indicates upstream/gateway error, instead of short-circuiting on the status code check.

Suggested change
if (statusCode !== undefined) {
if (statusCode !== undefined) {
// Treat non-HTTP / sentinel status codes (e.g. 0) as upstream/gateway signals
// and fall back to unified_finish_reason-based logic.
if (statusCode < 100) {
return (
logRow.unified_finish_reason === null ||
NOTIFIABLE_PROVIDER_ERROR_REASONS.has(logRow.unified_finish_reason)
);
}
// For real HTTP status codes, only notify on server errors.

Copilot uses AI. Check for mistakes.
Comment thread apps/worker/src/worker.ts Outdated
Comment on lines +881 to +885
await Promise.all(
providerErrorLogs.map(async (providerErrorLog) => {
await notifyProviderError(providerErrorLog);
}),
);
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Promise.all will fire one webhook request per notifiable log (up to BATCH_SIZE) concurrently. This can easily trigger Discord rate limits and can also create a burst of outbound requests from the worker. Consider adding a small concurrency limit / batching strategy (e.g., process sequentially or with a capped pool) to smooth traffic and reduce the chance of webhook failures.

Suggested change
await Promise.all(
providerErrorLogs.map(async (providerErrorLog) => {
await notifyProviderError(providerErrorLog);
}),
);
for (const providerErrorLog of providerErrorLogs) {
await notifyProviderError(providerErrorLog);
}

Copilot uses AI. Check for mistakes.
Comment on lines +141 to +147
const response = await fetch(providerErrorDiscordUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(buildDiscordEmbed(log)),
});
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Discord payload includes provider/gateway response text and model/provider strings, which may contain @everyone / @here / role mentions (untrusted input). Without allowed_mentions set, the webhook can generate unwanted pings in Discord. Consider including allowed_mentions: { parse: [] } (or equivalent) in the webhook JSON body to disable mention parsing.

Copilot uses AI. Check for mistakes.
Comment on lines +141 to +147
const response = await fetch(providerErrorDiscordUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(buildDiscordEmbed(log)),
});
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fetch to the Discord webhook has no timeout/abort handling. If Discord (or the network) stalls, batchProcessLogs() will await these requests (via Promise.all) and the worker can get stuck processing the batch. Consider adding an AbortController with a reasonable timeout and ensuring the request is aborted/handled cleanly.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/worker/src/services/provider-error-discord.ts`:
- Around line 141-147: The fetch call in notifyProviderError (using
providerErrorDiscordUrl and buildDiscordEmbed) needs a hard timeout to avoid
hanging the Promise.all; add an AbortController, pass its signal to fetch, start
a setTimeout (e.g. 3–5s) that calls controller.abort(), and clear the timeout
after fetch completes; also catch abort/fetch errors inside notifyProviderError
so an aborted webhook or network error is logged and does not propagate to block
the caller.

In `@apps/worker/src/worker.ts`:
- Around line 880-886: The code is awaiting outbound webhook calls
(providerErrorLogs.map -> notifyProviderError) while the credit-processing lock
is still held, which can extend lock duration; to fix, stop awaiting these calls
inside the locked section by moving the notifyProviderError invocation(s) to
after the lock is released or dispatching them as non-blocking (fire-and-forget)
tasks; specifically locate the providerErrorLogs handling and either (a)
relocate the Promise.all(providerErrorLogs.map(... notifyProviderError ...)) so
it executes after the lock release point, or (b) call notifyProviderError
without await (or schedule via setImmediate/queue) so the lock-holding function
returns immediately. Ensure notifyProviderError remains called for each
providerErrorLog but no outbound-awaits occur while the lock is held.
- Around line 143-151: The current logic lets a present statusCode short-circuit
notifications which suppresses explicit provider reasons; change the decision
order so you first check logRow.unified_finish_reason (and return true if it's
null or in NOTIFIABLE_PROVIDER_ERROR_REASONS) and only if that check doesn't
trigger consult statusCode (logRow.error_details?.statusCode) returning
statusCode >= 500; update the logic around unified_finish_reason,
NOTIFIABLE_PROVIDER_ERROR_REASONS, and statusCode in the function in worker.ts
so provider error reasons always cause notification regardless of a non-5xx
status.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a7b225bc-35d2-446d-ae63-45560bdff410

📥 Commits

Reviewing files that changed from the base of the PR and between d1ba037 and acd2480.

📒 Files selected for processing (3)
  • apps/worker/src/log-processing.spec.ts
  • apps/worker/src/services/provider-error-discord.ts
  • apps/worker/src/worker.ts

Comment thread apps/worker/src/services/provider-error-discord.ts Outdated
Comment thread apps/worker/src/worker.ts Outdated
Comment on lines +143 to +151
const statusCode = logRow.error_details?.statusCode;
if (statusCode !== undefined) {
return statusCode >= 500;
}

return (
logRow.unified_finish_reason === null ||
NOTIFIABLE_PROVIDER_ERROR_REASONS.has(logRow.unified_finish_reason)
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don’t let HTTP status override explicit provider error reasons.

On Lines 143-146, a present statusCode short-circuits the decision. That suppresses notifications for explicit gateway_error / upstream_error whenever status is <500, which breaks the intended behavior.

🔧 Proposed fix
 function shouldNotifyProviderError(logRow: ProcessedLogRow): boolean {
 	if (logRow.hasError !== true) {
 		return false;
 	}

 	if (logRow.unified_finish_reason === "client_error") {
 		return false;
 	}

-	const statusCode = logRow.error_details?.statusCode;
-	if (statusCode !== undefined) {
-		return statusCode >= 500;
-	}
-
-	return (
-		logRow.unified_finish_reason === null ||
-		NOTIFIABLE_PROVIDER_ERROR_REASONS.has(logRow.unified_finish_reason)
-	);
+	if (logRow.unified_finish_reason !== null) {
+		return NOTIFIABLE_PROVIDER_ERROR_REASONS.has(logRow.unified_finish_reason);
+	}
+
+	const statusCode = logRow.error_details?.statusCode;
+	return statusCode !== undefined && statusCode >= 500;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/worker/src/worker.ts` around lines 143 - 151, The current logic lets a
present statusCode short-circuit notifications which suppresses explicit
provider reasons; change the decision order so you first check
logRow.unified_finish_reason (and return true if it's null or in
NOTIFIABLE_PROVIDER_ERROR_REASONS) and only if that check doesn't trigger
consult statusCode (logRow.error_details?.statusCode) returning statusCode >=
500; update the logic around unified_finish_reason,
NOTIFIABLE_PROVIDER_ERROR_REASONS, and statusCode in the function in worker.ts
so provider error reasons always cause notification regardless of a non-5xx
status.

Comment thread apps/worker/src/worker.ts Outdated
@steebchen steebchen force-pushed the provider-discord-pr branch from acd2480 to ce90aa2 Compare April 5, 2026 08:00
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ce90aa2f54

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/worker/src/worker.ts Outdated
Comment on lines +995 to +1000
if (providerErrorLogs.length > 0) {
await Promise.all(
providerErrorLogs.map(async (providerErrorLog) => {
await notifyProviderError(providerErrorLog);
}),
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Release processing lock before sending Discord webhooks

batchProcessLogs keeps the CREDIT_PROCESSING lock until every notifyProviderError call completes. Since these webhook POSTs are network-bound and have no timeout, a slow or unreachable Discord endpoint can hold the lock for an extended period, so later worker ticks fail to acquire the lock and skip log processing/credit deductions for everyone. Send notifications after releasing the lock (or enforce a strict timeout/background queue) so billing throughput is not blocked by webhook latency.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
apps/worker/src/worker.ts (1)

215-223: ⚠️ Potential issue | 🟠 Major

HTTP status check overrides explicit provider error reasons.

When statusCode is present, the check on Lines 216-218 short-circuits the decision. This suppresses notifications for explicit gateway_error / upstream_error whenever status is <500 (e.g., 429 rate-limit errors).

Consider reordering so explicit finish reasons take precedence:

🔧 Proposed fix
 function shouldNotifyProviderError(logRow: ProcessedLogRow): boolean {
 	if (logRow.hasError !== true) {
 		return false;
 	}

 	if (logRow.unified_finish_reason === "client_error") {
 		return false;
 	}

-	const statusCode = logRow.error_details?.statusCode;
-	if (statusCode !== undefined) {
-		return statusCode >= 500;
-	}
-
-	return (
-		logRow.unified_finish_reason === null ||
-		NOTIFIABLE_PROVIDER_ERROR_REASONS.has(logRow.unified_finish_reason)
-	);
+	if (logRow.unified_finish_reason !== null) {
+		return NOTIFIABLE_PROVIDER_ERROR_REASONS.has(logRow.unified_finish_reason);
+	}
+
+	const statusCode = logRow.error_details?.statusCode;
+	return statusCode !== undefined && statusCode >= 500;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/worker/src/worker.ts` around lines 215 - 223, The logic currently
short-circuits on statusCode and suppresses explicit provider finish reasons;
change the order so checks on logRow.unified_finish_reason happen first: if
logRow.unified_finish_reason is non-null return true when
NOTIFIABLE_PROVIDER_ERROR_REASONS.has(logRow.unified_finish_reason) (i.e., treat
explicit provider errors as notifiable regardless of HTTP status), otherwise
fall back to checking logRow.error_details?.statusCode and return statusCode >=
500; if neither applies return false. Use the existing symbols
logRow.unified_finish_reason, NOTIFIABLE_PROVIDER_ERROR_REASONS and
logRow.error_details?.statusCode to locate and update the code path.
🧹 Nitpick comments (1)
apps/worker/src/worker.ts (1)

995-1001: Simplify redundant async wrapper.

The inner async function and nested await are unnecessary since notifyProviderError already returns a Promise. This can be simplified:

♻️ Suggested simplification
 		if (providerErrorLogs.length > 0) {
 			await Promise.all(
-				providerErrorLogs.map(async (providerErrorLog) => {
-					await notifyProviderError(providerErrorLog);
-				}),
+				providerErrorLogs.map((providerErrorLog) =>
+					notifyProviderError(providerErrorLog),
+				),
 			);
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/worker/src/worker.ts` around lines 995 - 1001, The map callback wrapping
notifyProviderError in an unnecessary async function causes redundant await
nesting; replace the providerErrorLogs.map(async (providerErrorLog) => { await
notifyProviderError(providerErrorLog); }) with a direct call so Promise.all
receives the notifyProviderError promises (e.g., use
providerErrorLogs.map(providerErrorLog => notifyProviderError(providerErrorLog))
or simply providerErrorLogs.map(notifyProviderError)) to eliminate the extra
async/await while keeping the same behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@apps/worker/src/worker.ts`:
- Around line 215-223: The logic currently short-circuits on statusCode and
suppresses explicit provider finish reasons; change the order so checks on
logRow.unified_finish_reason happen first: if logRow.unified_finish_reason is
non-null return true when
NOTIFIABLE_PROVIDER_ERROR_REASONS.has(logRow.unified_finish_reason) (i.e., treat
explicit provider errors as notifiable regardless of HTTP status), otherwise
fall back to checking logRow.error_details?.statusCode and return statusCode >=
500; if neither applies return false. Use the existing symbols
logRow.unified_finish_reason, NOTIFIABLE_PROVIDER_ERROR_REASONS and
logRow.error_details?.statusCode to locate and update the code path.

---

Nitpick comments:
In `@apps/worker/src/worker.ts`:
- Around line 995-1001: The map callback wrapping notifyProviderError in an
unnecessary async function causes redundant await nesting; replace the
providerErrorLogs.map(async (providerErrorLog) => { await
notifyProviderError(providerErrorLog); }) with a direct call so Promise.all
receives the notifyProviderError promises (e.g., use
providerErrorLogs.map(providerErrorLog => notifyProviderError(providerErrorLog))
or simply providerErrorLogs.map(notifyProviderError)) to eliminate the extra
async/await while keeping the same behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ed795612-0c9b-49f7-bf1c-9feba583b940

📥 Commits

Reviewing files that changed from the base of the PR and between acd2480 and ce90aa2.

📒 Files selected for processing (3)
  • apps/worker/src/log-processing.spec.ts
  • apps/worker/src/services/provider-error-discord.ts
  • apps/worker/src/worker.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/worker/src/services/provider-error-discord.ts

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/worker/src/services/provider-error-discord.ts`:
- Around line 57-69: formatErrorDescription currently forwards raw responseText
and other parts of ErrorDetails to Discord; redact sensitive stable identifiers
(requestId, projectId, organizationId, traceId, logId) and any PII before
sending. Modify formatErrorDescription to sanitize errorDetails.responseText
(and any other text fields) by removing/masking those identifier keys with a
deterministic redaction (e.g., replace values with "<redacted>" or hash) using a
regex or JSON-parsing-safe sanitizer, ensure errorDetails.cause and status lines
are preserved but scrubbed, and apply the same sanitizer to the code paths that
build the payload around lines referenced (where requestId/projectId/etc. are
added) so none of those raw IDs are forwarded to the Discord webhook; use
functions like sanitizeErrorText or redactSensitiveIds and call them from
formatErrorDescription and the code that constructs the webhook payload.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 2a24a10b-ef1c-4e35-a81c-e9d8ec1b9ac3

📥 Commits

Reviewing files that changed from the base of the PR and between ce90aa2 and c202fc1.

📒 Files selected for processing (3)
  • apps/worker/src/log-processing.spec.ts
  • apps/worker/src/services/provider-error-discord.ts
  • apps/worker/src/worker.ts

Comment thread apps/worker/src/services/provider-error-discord.ts Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1ad624c672

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/worker/src/worker.ts
Comment on lines +219 to +220
const statusCode = logRow.error_details?.statusCode;
return statusCode !== undefined && statusCode >= 500;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Classify null finish reasons beyond 5xx statuses

When unified_finish_reason is missing, shouldNotifyProviderError currently only notifies for statusCode >= 500. That skips provider/gateway failures like 429/404 (upstream_error) and 401/403 (gateway_error), even though the gateway’s canonical classifier (apps/gateway/src/chat/tools/get-finish-reason-from-error.ts) treats those statuses as non-client errors. The fallback path was added specifically for missing finish reasons, so these cases will silently miss Discord alerts.

Useful? React with 👍 / 👎.

@steebchen steebchen force-pushed the provider-discord-pr branch from 1ad624c to 5a7da10 Compare April 20, 2026 20:18
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
apps/worker/src/worker.ts (1)

1013-1019: Optional: use Promise.allSettled to future-proof the fan-out.

Today notifyProviderError catches all errors internally, so Promise.all won't reject in practice. However, if a future refactor ever lets an error escape (e.g., a synchronous throw in buildDiscordEmbed before the try, or a change to rethrow on non-2xx), Promise.all would abandon the remaining notifications. Promise.allSettled makes the guarantee structural rather than reliant on the callee's internal error handling.

♻️ Suggested change
-	if (shouldSendProviderErrorNotifications && providerErrorLogs.length > 0) {
-		await Promise.all(providerErrorLogs.map(notifyProviderError));
-	}
+	if (shouldSendProviderErrorNotifications && providerErrorLogs.length > 0) {
+		await Promise.allSettled(providerErrorLogs.map(notifyProviderError));
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/worker/src/worker.ts` around lines 1013 - 1019, The fan-out using
Promise.all for provider error notifications is brittle if a future change lets
notifyProviderError throw; replace the Promise.all call with Promise.allSettled
to ensure all notifyProviderError calls run to completion regardless of
individual failures. Locate the block that checks
shouldSendProviderErrorNotifications and providerErrorLogs and change the await
Promise.all(providerErrorLogs.map(notifyProviderError)) to await
Promise.allSettled(providerErrorLogs.map(notifyProviderError)); keep the
surrounding condition and the untouched low-balance call to
checkLowBalanceAlerts(deductedOrgIds).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/worker/src/worker.ts`:
- Around line 1013-1019: The fan-out using Promise.all for provider error
notifications is brittle if a future change lets notifyProviderError throw;
replace the Promise.all call with Promise.allSettled to ensure all
notifyProviderError calls run to completion regardless of individual failures.
Locate the block that checks shouldSendProviderErrorNotifications and
providerErrorLogs and change the await
Promise.all(providerErrorLogs.map(notifyProviderError)) to await
Promise.allSettled(providerErrorLogs.map(notifyProviderError)); keep the
surrounding condition and the untouched low-balance call to
checkLowBalanceAlerts(deductedOrgIds).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: fa5e7557-92a7-4b95-a1c9-6780bdb778ba

📥 Commits

Reviewing files that changed from the base of the PR and between 1ad624c and 5a7da10.

📒 Files selected for processing (3)
  • apps/worker/src/log-processing.spec.ts
  • apps/worker/src/services/provider-error-discord.ts
  • apps/worker/src/worker.ts
✅ Files skipped from review due to trivial changes (1)
  • apps/worker/src/log-processing.spec.ts

@steebchen steebchen force-pushed the provider-discord-pr branch from 5a7da10 to 334b5d1 Compare April 22, 2026 11:02
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 334b5d1728

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/worker/src/worker.ts
Comment on lines +1013 to +1014
if (deductedOrgIds.length > 0) {
void checkLowBalanceAlerts(deductedOrgIds);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Guard low-balance checks behind transaction success

After this change, checkLowBalanceAlerts runs outside the try block, so it executes even when the credit-deduction transaction throws and rolls back. Because deductedOrgIds is populated before the transaction completes, a late failure (for example in referral or API-key updates) can still trigger low-balance emails for orgs whose balance was never actually reduced. This creates false customer alerts and should be gated on successful transaction completion (similar to shouldSendProviderErrorNotifications).

Useful? React with 👍 / 👎.

@steebchen steebchen force-pushed the provider-discord-pr branch from 334b5d1 to 0879878 Compare April 23, 2026 09:23
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0879878d58

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/worker/src/worker.ts
Comment on lines +224 to +225
const statusCode = logRow.error_details?.statusCode;
return statusCode !== undefined && statusCode >= 500;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Broaden null-reason fallback beyond 5xx

When unified_finish_reason is missing, this fallback only notifies for statusCode >= 500, so provider/gateway failures like 429, 404, 401, and 403 are silently skipped. That conflicts with the gateway’s own error classifier (apps/gateway/src/chat/tools/get-finish-reason-from-error.ts), which treats those statuses as non-client errors, so missing/legacy rows with null finish reason will under-report real provider incidents.

Useful? React with 👍 / 👎.

Comment thread apps/worker/src/worker.ts
Comment on lines +1013 to +1014
if (deductedOrgIds.length > 0) {
void checkLowBalanceAlerts(deductedOrgIds);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Run low-balance alerts only after successful commit

deductedOrgIds is populated inside the transaction before all writes complete, but checkLowBalanceAlerts now runs unconditionally after the try/catch block. If any later statement in the transaction fails and rolls back, this can still send low-balance emails for orgs whose credits were never actually deducted, producing false customer alerts.

Useful? React with 👍 / 👎.

@steebchen steebchen force-pushed the provider-discord-pr branch from 0879878 to 613c6d7 Compare May 7, 2026 18:34
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants