You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(actions)!: failures speak HTTP — rejections are 400, success is a single wrap (#3962)
The 200-with-inner-envelope wire was never a designed contract: no ADR or doc
specified it, it originated as the catch block reusing deps.success(), and
/actions was the only route of 12 that double-wrapped. #3962 (platform
decision: third-party-facing API, normalized results) classifies it as a bug.
Contract now, identical to /data: 200 single wrap (data = handler return
value); deliberate rejection (body throw / flow rejection / ValidationError)
400 via errorFromThrown with code/fields in details; dispatch failures
404/403/400/503 and crashes 500 unchanged (#3930/#3951). A rejected flow
regains code FLOW_FAILED at 400. The #3951 name discriminator now selects
400 vs 500.
actions-validation-envelope.test.ts is flipped citing #3962 — the previous
revision pinned 200 explicitly so that flipping it would be "a conscious,
documented decision, not a side effect"; #3962 is that decision.
client.actions.invoke/invokeGlobal still never throw: they fold every failure
status into {success:false, error}, read the single wrap on success, and keep
a NARROW legacy heuristic (boolean success + no foreign keys) so a current SDK
still folds pre-#3962 double-wrapped 200s.
Migration for raw-HTTP callers: branch on the status; on 200, data is the
handler's return value directly. SDK callers need no change.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011AvZj6cLX7APd7roh2eK4F
0 commit comments