th-df7007/th-e7ef23: stop swallowing the exception behind INTERNAL_ERROR; fix .NET gateway env vars - #336
Merged
Merged
Conversation
…st reads SMOOAI_* gateway vars The .NET server returned INTERNAL_ERROR on every send_message and logged nothing at all about why — both catch sites in FrameDispatcher discarded the exception. Route them through LogInternalError (action + requestId + stack at Error level, stderr fallback with no ILogger); the wire message stays generic. That logging immediately named the cause: HTTP 401 'LiteLLM Virtual Key expected. Received=****'. The host read SMOOTH_GATEWAY_URL/KEY/MODEL while rust, go, ts and python all read the SMOOAI_* spelling, so every launcher and bench that exports the shared contract left the .NET host keyless. Read SMOOAI_* first, keep SMOOTH_* as a fallback. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P83HrAKaqp2ehxQcW7m6QU
…ERROR too Same class of bug as the .NET fix: the Go dispatcher dropped err at all seven of its INTERNAL_ERROR sites, the Python dispatcher dropped the exception at both of its own. Go now routes them through one internalError chokepoint that slog.Errors first; Python logs with logging.exception. Wire messages unchanged (still generic, still leak nothing). TypeScript already logged; Rust puts the detail on the wire. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P83HrAKaqp2ehxQcW7m6QU
🦋 Changeset detectedLatest commit: bcfe4a9 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Running the smooth-bench agentic suite across all five engines, the .NET server booted fine, accepted the WebSocket upgrade (HTTP 101 on
/ws), and then returnedINTERNAL_ERROR: Internal error processing the request.for everysend_message. Zero tool calls, every scenario INCONCLUSIVE.Worse: the .NET server logged nothing about the failure. No exception, no stack, at any level. Both places
FrameDispatchermaps an exception toINTERNAL_ERRORdiscarded it outright.Fix 1 — observability (th-e7ef23)
FrameDispatcheralready carried anILogger?(wired from DI atSmoothOperatorWebSocketExtensions.cs:107) but never used it at either catch site. Both now route throughLogInternalError, which records action + requestId + the exception with its stack atErrorlevel, falling back to stderr when no logger is wired. The wire message is unchanged — still generic, still leaks nothing to the client.Same swallow existed in the siblings: the Go dispatcher dropped
errat all seven of itsINTERNAL_ERRORsites (now oneinternalErrorchokepoint thatslog.Errors first), and the Python dispatcher dropped the exception at both of its own (nowlogging.exception). TypeScript already logged viaconsole.error; Rust puts the detail on the wire.Fix 2 — root cause (th-df7007)
The new logging named it on the first run:
dotnet/server/host/Program.csreadSMOOTH_GATEWAY_URL/SMOOTH_GATEWAY_KEY/SMOOTH_MODEL. Rust, Go, TS and Python all read theSMOOAI_*spelling — the actual cross-engine contract. Every launcher and bench exporting the shared names left the .NET host keyless, so it called the gateway with the literal key"unset".SMOOAI_*now wins;SMOOTH_*kept as a fallback for existing deployments. README + Dockerfile updated.Verification
Before (bench,
no-over-refusal, deepseek-v4-flash, host isolation):INCONCLUSIVE,INTERNAL_ERROR, 0 tool calls.After:
/healthreportsdeepseek-v4-flash(was silentlyclaude-haiku-4-5), turns stream tokens, and the bench scenario runs conclusively with real tool calls (read_file,bash,list_files,grep). ZeroINTERNAL_ERRORacross every scenario's engine log.Tests
dotnet/server/tests/InternalErrorLoggingTests.cs— 3 tests: turn-path logging, dispatcher-path logging, and the no-logger fallback. Asserts the generic message on the wire AND the detail in the log.go/server/internal_error_log_test.go— same contract overslog.python/server/tests/test_internal_error_logging.py— same contract overcaplog.Full suites green: .NET 294 passed, Go all packages ok, Python 231 passed / 1 skipped.
🤖 Generated with Claude Code
https://claude.ai/code/session_01P83HrAKaqp2ehxQcW7m6QU