Description
Two settlement paths record failures as success on Bedrock:
POST /api/session/:id/generate returns {"data":{"text":""}} with HTTP 200 when the stream finishes content_filtered, or finishes max_tokens without any text or tool call.
- In the runner, a step finishing
max_tokens with reasoning-only output (no text, no tool call) settles as succeeded. The user sees an empty assistant message recorded as success.
The filtered terminal segment also stays in session history: replaying a real session with its full history returns empty text on every subsequent generation, and removing just the content_filtered segment makes the same history respond normally again.
In an audit of two workspaces (~1,500 sessions), 194 Fable sessions and 10 Opus sessions were recorded succeeded with assistant messages containing no text and no tool calls; 552 turns held reasoning only after hitting max_tokens.
I have a fix ready and will open a PR: session.generate raises ContentPolicyError on content-filter and InvalidProviderOutputError on output-less length; the runner publisher settles reasoning-only length as provider.invalid-output while keeping the reasoning and rawFinish for diagnosis. Truncated responses with partial text remain successful.
Plugins
opencode-bedrock-rotate (bearer token rotation; not related)
OpenCode version
0.0.0-beta-18743, also reproduced on 0.0.0-dev-18806
Steps to reproduce
- Get a Bedrock response that ends
content_filtered (or max_tokens spent entirely on reasoning, e.g. adaptive thinking with a low effective budget).
- The step settles as succeeded with an empty assistant message.
POST /api/session/:id/generate on that session returns {"data":{"text":""}} with HTTP 200 from then on.
Description
Two settlement paths record failures as success on Bedrock:
POST /api/session/:id/generatereturns{"data":{"text":""}}with HTTP 200 when the stream finishescontent_filtered, or finishesmax_tokenswithout any text or tool call.max_tokenswith reasoning-only output (no text, no tool call) settles assucceeded. The user sees an empty assistant message recorded as success.The filtered terminal segment also stays in session history: replaying a real session with its full history returns empty text on every subsequent generation, and removing just the
content_filteredsegment makes the same history respond normally again.In an audit of two workspaces (~1,500 sessions), 194 Fable sessions and 10 Opus sessions were recorded
succeededwith assistant messages containing no text and no tool calls; 552 turns held reasoning only after hittingmax_tokens.I have a fix ready and will open a PR:
session.generateraisesContentPolicyErroroncontent-filterandInvalidProviderOutputErroron output-lesslength; the runner publisher settles reasoning-onlylengthasprovider.invalid-outputwhile keeping the reasoning andrawFinishfor diagnosis. Truncated responses with partial text remain successful.Plugins
opencode-bedrock-rotate (bearer token rotation; not related)
OpenCode version
0.0.0-beta-18743, also reproduced on 0.0.0-dev-18806
Steps to reproduce
content_filtered(ormax_tokensspent entirely on reasoning, e.g. adaptive thinking with a low effective budget).POST /api/session/:id/generateon that session returns{"data":{"text":""}}with HTTP 200 from then on.