Relationships
#3773 A coded UserError a model method throws reaches a workflow step without its code, because InProcessExecutor keeps only the message
Opened by zack · 10/22/2026· Shipped 10/22/2026
Problem
swamp-club#3748 records a failed workflow step's stable error code: the job loop in WorkflowExecutionService reads error instanceof UserError ? error.code : undefined and puts it on the step_failed event, the StepRun record and swamp workflow run --json. That works for a UserError swamp throws itself, such as the evaluated_cache_holds_sensitive_arguments refusal. It never works for a coded UserError that a model method's own execute throws.
InProcessExecutor.execute (src/domain/models/in_process_executor.ts, both catch branches) turns the thrown error into { status: "error", error: error.message, errorPaths }. MethodExecutionService then rethrows new Error(executionResult.error) with the paths and data handles attached. The class and the code are gone before DefaultStepExecutor sees the error, so the step records no errorCode.
Found while porting swamp-club#3746: a scratch integration run had a model method throw new UserError("intentional failure plain", "auth_failed") with no secret in it, and the step still recorded errorCode: undefined. The #3748 unit test passes because it drives a fake StepExecutor that rejects with the UserError directly, bypassing the in-process path.
Fix
InProcessExecutor: carry the thrown error's code in the error result, aserrorPathsis carried, when the error is aUserErrorwith a code.MethodExecutionService: rethrow aUserErrorwith that code (keeping the marked paths and the attached data handles) when the result carries one, and a plainErrorotherwise.- Check whether the remote-execution result path (the worker runner protocol) needs the same field.
Files
src/domain/models/in_process_executor.tssrc/domain/models/method_execution_service.ts- the executor result type the two share
Tests
in_process_executor_test.ts: a method that throws a codedUserErroryields an error result with its code; an uncoded or plain error yields none.- An integration test through the real
WorkflowExecutionServiceandDefaultStepExecutor: a model method that throwsnew UserError(..., "auth_failed")gives the steperrorCode: "auth_failed"on thestep_failedevent and the run record.
Shipped
Click a lifecycle step above to view its details.
Sign in to post a ripple.