Skip to content

fix(server): log why a remote chat call failed, and warn when an upstream key is unset - #738

Merged
krisztian-gajdar merged 6 commits into
mainfrom
fix/remote-chat-failure-logs
Oct 14, 2026
Merged

krisztian-gajdar merged 6 commits into
mainfrom
fix/remote-chat-failure-logs

Conversation

@krisztian-gajdar

@krisztian-gajdar krisztian-gajdar commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Problem

On a single node, POST /v1/chat/completions for a remote profile answers a failed upstream call with 502 upstream_error: upstream generation request failed (or a 503), and the server log shows only the access line. The server already holds a fixed reason for each failure, for example upstream answered 401 or the upstream credential is unavailable, but the route dropped it. An upstream that could not be reached was silent on every generation route, and native /v1/generate streamed was silent for any failure before output. An upstream whose api_key_secret variable was unset also started without a word and then failed every request.

Change

  • Single-node remote chat (502 and after output). The route logs remote chat for <model> failed: <reason> at WARNING, or remote chat for <model> failed after output: <reason> when a stream fails after its first event. An OpenAI-compatible answer that carries an error object in place of the chat answer is reported as upstream sent an error instead of a chat answer. These lines and their tests are commit 2a8d1a2 from feat(examples): run the OpenCode example on self-hosted SIE with an OpenRouter upstream #735, carried here unchanged. feat(examples): run the OpenCode example on self-hosted SIE with an OpenRouter upstream #735 picks them up from main when it next merges it.
  • Unreachable upstream (503). Single-node chat logs it on the same line, for example remote chat for <model> failed: upstream 'chat-api' is unavailable: request failed (ConnectError). Native generation, completions, and chat the server renders through the model's template reach the upstream through the remote adapters' generate, which turns the failure into a retryable capacity error and drops its reason. They now log remote generation failed: <reason> at that point, once per call.
  • Native /v1/generate streamed, before output. A failure there answered 500 with no log line. It now logs stream_generate failed before output with the traceback, as the buffered (generate failed for <model>) and after-output (stream_generate failed mid-stream) paths of the same route already do.
  • Unset credential at startup. When an upstream's credential variable is unset, blank or holds characters a credential cannot contain, startup logs one WARNING naming the upstream and the variable. The check is the one each request already runs (Upstream.api_key()). The server still starts and still reads the variable for every request, as config/upstreams.py and REMOTE_BACKENDS.md describe.
  • REMOTE_BACKENDS.md states both, next to the credential example and the failure behaviour.

What an operator now sees (model org/model, upstream chat-api, variable CHAT_API_KEY):

requests to upstream 'chat-api' fail until its credential is usable: environment variable CHAT_API_KEY is not set
remote chat for org/model failed: the upstream credential is unavailable
remote chat for org/model failed: upstream answered 401
remote chat for org/model failed: upstream answered 404
remote chat for org/model failed: upstream 'chat-api' is unavailable: request failed (ConnectError)
remote chat for org/model failed after output: the upstream failed during chat generation
remote generation failed: upstream 'chat-api' is unavailable: request failed (ConnectError)

No line contains the credential, the prompt, or anything the upstream sent. Every reason is text the server builds itself. A refused input (400) is already logged by open_stream as upstream '<name>' refused a generation request: ....

Every remote generation path, after this change

Checked on the same scripted upstream (401, 404, connection failure, failure after output), for both upstream kinds:

Path Failure before output Unreachable upstream After output
Chat, single node remote chat for <model> failed: <reason> same line ... failed after output: <reason>
Chat rendered through the template remote chat for <model> failed: <reason> remote generation failed: <reason> ... failed after output: <reason>
Native /v1/generate, buffered generate failed for <model> + traceback (unchanged) remote generation failed: <reason> n/a
Native /v1/generate, streamed stream_generate failed before output + traceback remote generation failed: <reason> stream_generate failed mid-stream + traceback (unchanged)
/v1/completions OpenAI completion failed ... + traceback (unchanged) remote generation failed: <reason> unchanged
Queued worker Generate iterator raised for <request>/<attempt> + traceback (unchanged) native generation also logs remote generation failed: <reason> unchanged

All are WARNING. The queued worker already logged every failure, so it is unchanged except for the adapter line, which adds the transport reason that its capacity error does not carry.

Classification

Ordinary review path. This is not an authentication or authorization change: how the upstream credential is read, sent and enforced is unchanged. The startup check calls the same Upstream.api_key() that each request already calls, keeps nothing, and logs only the variable's name.

Tests

  • From 2a8d1a2: a 401 and a missing key on the chat route, streamed and buffered, failures after output, and the error-object parser case.
  • test_a_remote_generation_failure_logs_one_warning_with_its_reason: the real routes with a MockTransport upstream. Chat 404 and connection failure, rendered-template chat 401 and connection failure, native and completions connection failure, each streamed and buffered, for both upstream kinds (24 cases). Each asserts exactly one WARNING with its logger and exact text, that the configured credential was sent as the bearer token, and that a canary credential, the prompt and the upstream's error text never reach the captured log at DEBUG.
  • test_a_native_remote_failure_before_output_logs_one_warning_with_its_reason: native 401, buffered and streamed, one warning whose exception is upstream answered 401.
  • test_startup_warns_about_an_unusable_credential_and_still_starts: AppFactory.create_app with an upstreams file, for an unset, blank, unusable and set variable. It asserts one warning or none, that both upstreams are installed, and that the canary value never reaches the log.

Mutations, each caught: no chat log on a 502, on an unreachable upstream, or after output; the chat 502 line at INFO or logging the request body; the route also logging the rendered-template capacity error (two lines); no adapter line in either adapter; the adapter line logging the transport exception; no native before-output line, or the line without its traceback; no startup warning; the startup warning logging the value; startup refusing to start; the startup check treating only an absent variable as unset.

Validation: mise run lint and mise run typecheck pass. mise run test -- packages/sie_server/tests gives 11764 passed and 5 failed on macOS; the 5 (tests/config/test_serving_artifacts.py, tests/core/test_model_loader_cache.py) fail identically with main's source, on read-only directory renames, and pass in CI.

…ream key is unset

The single-node remote chat route answered a failed upstream call with 502
or 503 and logged only the access line, although the server holds a fixed
reason for each failure. It now logs one WARNING per failed call with the
model, the upstream and that reason, including a stream that fails after
its first event and chat rendered through the model's template.

An upstream whose credential variable is unset, blank or unusable now logs
one WARNING at startup naming the upstream and the variable. The server
still starts and reads the variable for every request, as before.
@krisztian-gajdar
krisztian-gajdar requested a review from a team as a code owner October 14, 2026 18:46
@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Team
  • Run ID: e4044c75-0105-44f3-9ea2-3d2414eaecad
📥 Commits

Reviewing files that changed from the base of the PR and between dd7fbdc and 3cb0aa4.

📒 Files selected for processing: 9
  • packages/sie_server/REMOTE_BACKENDS.md
  • packages/sie_server/src/sie_server/adapters/remote/_openai_chat.py
  • packages/sie_server/src/sie_server/adapters/remote/openai.py
  • packages/sie_server/src/sie_server/adapters/remote/sie.py
  • packages/sie_server/src/sie_server/api/generate.py
  • packages/sie_server/src/sie_server/api/openai_local.py
  • packages/sie_server/tests/adapters/test_remote_openai_chat.py
  • packages/sie_server/tests/api/test_remote_chat.py
  • packages/sie_server/tests/config/test_upstreams.py
🚧 Files skipped from review as they are similar to previous changes: 2
  • packages/sie_server/REMOTE_BACKENDS.md
  • packages/sie_server/src/sie_server/api/openai_local.py

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 3 remain after this review.

📝 Walkthrough

The server now warns when upstream credentials are missing or invalid but continues startup. Remote chat and generation failures produce warning logs. Upstream chat error payloads produce a fixed error message that does not include the provider’s error detail.

Changes: Remote upstream warnings

Layer / File(s) Summary
Startup credential warnings
packages/sie_server/src/sie_server/config/upstreams.py, packages/sie_server/REMOTE_BACKENDS.md, packages/sie_server/tests/config/test_upstreams.py
Upstream installation checks each credential and logs a warning when it is unusable, then continues installation. Documentation and tests cover missing, blank, invalid, and usable credentials.
Upstream error parsing
packages/sie_server/src/sie_server/adapters/remote/_openai_chat.py, packages/sie_server/tests/adapters/test_remote_openai_chat.py
Chat payloads with an error key now produce a fixed upstream error message. Tests cover buffered and streamed responses and check that the provider’s error detail is not repeated.
Failure warning logs
packages/sie_server/src/sie_server/adapters/remote/openai.py, packages/sie_server/src/sie_server/adapters/remote/sie.py, packages/sie_server/src/sie_server/api/generate.py, packages/sie_server/src/sie_server/api/openai_local.py, packages/sie_server/REMOTE_BACKENDS.md, packages/sie_server/tests/api/test_remote_chat.py
Remote generation and chat failure paths now log warnings, including failures after streaming output begins. Documentation and tests cover warning reasons, response behavior, and exclusion of credentials, prompts, and upstream content from logs.

Suggested reviewers: svonava

Priority: ⬇️ Low

Merge Risk: ⚪ Minimal · up to 3cb0a

The new warnings make upstream failures more visible without a demonstrated change to caller responses or exposure of sensitive data. No merge-blocking issue was identified.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 22 functions across 9 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly summarizes the main changes: logging remote chat failures and warning when an upstream credential is unset.
Full details: Docstring Coverage

Explanation

Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 22 functions across 9 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

coderabbitai[bot]
coderabbitai Bot previously approved these changes Oct 14, 2026
Krisztian Gajdar added 4 commits October 14, 2026 21:07
The single-node remote chat route answered every refused or broken
upstream call with the same fixed 502 (or, after output, the same
in-stream error) and logged nothing but the access line, so a missing
upstream key, a 401, a 402, a 404 and an upstream error event all looked
the same to an operator.

The route now logs the failure's reason at warning level, for example
"the upstream credential is unavailable" or "upstream answered 401".
The reason is the server's own fixed text and repeats nothing the
upstream sent. The caller's answer is unchanged.

An OpenAI-compatible answer that carries an error object in place of the
chat answer, as an upstream sends when the provider behind it fails after
the 200, is now reported as "upstream sent an error instead of a chat
answer" rather than as an invalid chat response, so the log tells it
apart from an answer the parser refused.
A remote chat, native generation or completions request whose upstream
could not be reached answered 503 and logged nothing. Single-node chat now
logs the reason with the line it already uses for a 502. Native generation
and completions, and chat the server renders through the model's template,
log it from the remote adapters before the reason is mapped to a retryable
capacity error. A native streamed request that fails before output now logs
the failure as its buffered and after-output paths already do.
@krisztian-gajdar
krisztian-gajdar merged commit cd21333 into main Oct 14, 2026
21 checks passed
@krisztian-gajdar
krisztian-gajdar deleted the fix/remote-chat-failure-logs branch October 14, 2026 19:42
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.

1 participant