fix(proxy): classify Anthropic cache_control validation errors as 400, not 502 - #831
Merged
Conversation
…, not 502
Anthropic cache_control validation errors (breakpoint overflow past the
4-cap, or a ttl=1h breakpoint ordered after a ttl=5m one) previously fell
through ClassifyDispatchError to the generic "Upstream call failed" 502
handler — even though no upstream call was ever attempted. The router's
own translate-layer validator (internal/translate/cache_control.go)
rejects these before dispatch; the 502 path was both misleading (implies
an upstream failure that never happened) and didn't surface an
Anthropic-shaped error body for callers that parse one.
Now classified as a clean 400 (DispatchErrorAnthropicCacheControlInvalid),
matching the pattern used for the other client-input error kinds
(ErrRequestNotJSONObject, ErrInvalidRoutingKnobs, etc). unwrapToSentinelMessage
walks the error's wrap chain to the layer whose direct child is the sentinel
itself, so the client-facing message keeps the validator's dynamic detail
("got 5, maximum is 4") without leaking the internal "emit body: " wrap
prefix that every dispatch entry point adds.
Found by the router's real-Anthropic smoke suite (#828,
smoke/cache_test.go's overflow-rejection scenario) on its first run against
the real API — the in-process conformance suite never exercises what
ClassifyDispatchError actually returns for this sentinel pair end to end.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Claude finished @steventohme's task —— View job
One 4-line godoc block on |
workweave-bot
left a comment
Collaborator
There was a problem hiding this comment.
Advisory only — comment-length nit. Won't block merge.
What T-Rex did
Reviews (1): Last reviewed commit: "fix(proxy): classify Anthropic cache_con..." | Re-trigger Greptile |
Co-authored-by: workweave-bot <bot@workweave.ai>
|
Claude finished @steventohme's task —— View job
The 3-line godoc on |
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.
What
Anthropic
cache_controlvalidation errors (breakpoint overflow past the 4-cap, or attl=1hbreakpoint ordered after attl=5mone) previously fell throughClassifyDispatchErrorto the generic "Upstream call failed" 502 handler — even though no upstream call was ever attempted. The router's own translate-layer validator (internal/translate/cache_control.go) rejects these before dispatch.Now classified as a clean 400 (
DispatchErrorAnthropicCacheControlInvalid), matching the pattern used for the other client-input error kinds.unwrapToSentinelMessagewalks the error's wrap chain to strip the internal"emit body: "prefix while keeping the validator's own dynamic detail ("got 5, maximum is 4").Why
Found by the router's real-Anthropic smoke suite (#828,
smoke/cache_test.go's overflow-rejection scenario) on its first run against the real API — the in-process conformance suite never exercises whatClassifyDispatchErroractually returns for this sentinel pair end to end. Split out of #828 per review — that PR is the test harness; this is the standalone production fix it caught.Testing
go test ./internal/proxy/...— new unit tests assert 400 +IsClientError()+ no leaked wrap prefix for both the overflow and TTL-ordering sentinels.go build ./...,go vet ./...,gofmt -l .all clean.