-
Notifications
You must be signed in to change notification settings - Fork 10
Description
Problem
setCustomStatus() stores the raw object without serialization, and getCustomStatus() calls JSON.stringify() lazily. The problem is that getCustomStatus() is called outside the executor's try-catch block in orchestration-executor.ts (line 112):
try {
// ... process events (setCustomStatus called here) ...
} catch (e: unknown) {
ctx.setFailed(e instanceof Error ? e : new Error(String(e)));
}
// OUTSIDE try-catch — getCustomStatus() can throw here
return {
actions,
customStatus: ctx.getCustomStatus(), // JSON.stringify can throw!
};If a user passes a non-serializable value to setCustomStatus() (e.g., an object with circular references, or containing BigInt), JSON.stringify() throws a TypeError that is not caught by the executor. This causes the entire orchestration execution result to be lost — the sidecar never receives the completion actions, leaving the orchestration stuck.
Affected files
packages/durabletask-js/src/worker/runtime-orchestration-context.ts(lines 406-418)packages/durabletask-js/src/worker/orchestration-executor.ts(line 112)
Root Cause
Lazy serialization in getCustomStatus() defers JSON.stringify() to a point in the execution flow that is not protected by error handling. The executor's try-catch at lines 69-88 only covers event processing (where orchestrator code runs), not the result construction at lines 110-113.
Proposed Fix
Serialize eagerly in setCustomStatus() so that any serialization error is thrown inside orchestrator code (which runs within the executor's try-catch). Store the pre-serialized JSON string so getCustomStatus() becomes a trivial getter that cannot throw.
This ensures:
- Non-serializable values cause a clear error caught by the executor
- The orchestration properly fails with a descriptive error message
- The orchestration result is never silently lost
Impact
Severity: High — orchestration results are completely lost when this bug triggers.
Affected scenarios:
- Setting custom status with an object containing circular references
- Setting custom status with an object containing BigInt values
- Setting custom status with an object whose
toJSON()method throws
Without the fix, the orchestration appears stuck (sidecar never receives completion). With the fix, the orchestration properly fails with a clear "Custom status value is not JSON-serializable" error message.