-
Notifications
You must be signed in to change notification settings - Fork 9
Description
Problem
In packages/durabletask-js/src/worker/entity-executor.ts, the StateShim.setState() method (line 89–101) sets cachedValue before calling JSON.stringify(). When serialization fails (e.g., circular reference), the internal cache is left in an inconsistent state:
cachedValuepoints to the invalid (non-serializable) objectserializedValueretains the previous valid serialized state- If
cacheValidwastruefrom a priorgetState()orsetState(), the nextgetState()returns the invalid cached object instead of re-parsing the last valid serialized state
Root Cause
The assignment this.cachedValue = state on line 90 executes unconditionally before the try block that calls JSON.stringify(state). When JSON.stringify throws, the error is re-thrown but the cache is already corrupted. The cacheValid flag is not reset in the catch path, so if it was previously true, getState() skips re-parsing and returns the corrupted cachedValue.
Additionally, the error wrapping drops the original error cause — the { cause: e } option is not used.
Proposed Fix
- Move
this.cachedValue = stateinside thetryblock, afterJSON.stringify()succeeds - In the
catchblock, invalidate the cache (cacheValid = false,cachedValue = undefined) sogetState()falls back to re-parsing the last validserializedValue - Add
{ cause: e }to the error wrapper to preserve the original error chain
Impact
Severity: Medium — affects entity state consistency when entity code catches setState errors and attempts to recover by reading state.
Affected scenarios:
ITaskEntityimplementations that directly useoperation.state.setState()/operation.state.getState()and handle serialization errors gracefully- Any entity operation that catches a setState error and continues using state (reads corrupted cache instead of the last valid state)
Mitigating factor: The outer executeOperation() try/catch calls rollback() on any unhandled error, which resets the cache. The bug only manifests when entity code catches the setState error internally.