Two things left over from the #446 review that are real but do not belong in that branch.
Job bodies still reach Sentry through the exception chain
services/entry.py sets include_local_variables=False, and the comment above it names __cause__/__context__ walking as the reason. But disabling frame locals does not stop Sentry serialising the chained exception itself: entry.py:133 raises inside an except block, so the original exception travels as __context__ and its message goes to Sentry even though no frame does. For a PyYAML error that message quotes the offending line of workflow_yaml. The comment therefore claims a property the code does not have, which is worse than not having it.
The fix is a before_send that walks the chain and scrubs, rather than relying on any single flag. This is the same scrubber #654 needs for set_context, so the two should be done together.
Failure detail is now lost on every channel
The #446 branch removed exception text from every log line and error payload on the chat path, which was right as security and leaves operators with nothing. An operator seeing The workflow agent failed (RuntimeError) has the type and no stack, no message and no context, and there is no capture_exception anywhere in the global_chat path to make up for it. We traded one problem for another.
The honest fix is a scrubbed operator channel: capture_exception on the chat path once before_send is trusted to scrub, so Sentry gets the detail and the SSE stream does not. Until then, a production failure in the planner or a subagent is close to undebuggable from the logs alone.
Related: #654 (the set_context, llm_edit_answer and LoggingIntegration routes) and #655 (the Unicode gating work). The scrubber is the common dependency for this issue and #654.
Two things left over from the #446 review that are real but do not belong in that branch.
Job bodies still reach Sentry through the exception chain
services/entry.pysetsinclude_local_variables=False, and the comment above it names__cause__/__context__walking as the reason. But disabling frame locals does not stop Sentry serialising the chained exception itself:entry.py:133raises inside anexceptblock, so the original exception travels as__context__and its message goes to Sentry even though no frame does. For a PyYAML error that message quotes the offending line ofworkflow_yaml. The comment therefore claims a property the code does not have, which is worse than not having it.The fix is a
before_sendthat walks the chain and scrubs, rather than relying on any single flag. This is the same scrubber #654 needs forset_context, so the two should be done together.Failure detail is now lost on every channel
The #446 branch removed exception text from every log line and error payload on the chat path, which was right as security and leaves operators with nothing. An operator seeing
The workflow agent failed (RuntimeError)has the type and no stack, no message and no context, and there is nocapture_exceptionanywhere in theglobal_chatpath to make up for it. We traded one problem for another.The honest fix is a scrubbed operator channel:
capture_exceptionon the chat path oncebefore_sendis trusted to scrub, so Sentry gets the detail and the SSE stream does not. Until then, a production failure in the planner or a subagent is close to undebuggable from the logs alone.Related: #654 (the
set_context,llm_edit_answerandLoggingIntegrationroutes) and #655 (the Unicode gating work). The scrubber is the common dependency for this issue and #654.