-
Notifications
You must be signed in to change notification settings - Fork 11
[copilot-finds] Bug: newFailureDetails() drops error.cause chain, losing inner exception information #210
Description
Problem
The newFailureDetails() function in packages/durabletask-js/src/utils/pb-helper.util.ts (line 188) converts JavaScript errors into protobuf TaskFailureDetails messages but never populates the innerFailure field, even when the source error has a .cause property.
The protobuf TaskFailureDetails message has a recursive innerFailure field specifically designed to preserve error chains:
message TaskFailureDetails {
string errorType = 1;
string errorMessage = 2;
google.protobuf.StringValue stackTrace = 3;
TaskFailureDetails innerFailure = 4;
bool isNonRetriable = 5;
}
However, setInnerfailure() is never called anywhere in the codebase.
Root Cause
The newFailureDetails() function extracts name, message, and stack from the error but does not check for error.cause (the ES2022 standard for error chaining).
Impact
The codebase creates errors with { cause: ... } in 9+ places (client.ts, entity-executor.ts, pb-helper.util.ts). When these errors are reported as orchestration/activity failures, the inner cause information is completely lost. This makes debugging harder because:
parseJsonFieldwrapsSyntaxErrorin a descriptive error with{ cause: err }— the original parse error is lost- Client operations (rewind, restart) wrap gRPC errors with
{ cause: e }— the original gRPC error details are lost - Entity state serialization errors wrap the original error — the cause is lost
Cross-SDK impact: The .NET SDK populates InnerFailure from InnerException. The JS SDK should match this behavior.
Proposed Fix
Recursively populate innerFailure from error.cause in newFailureDetails(), with a depth limit (10) to guard against pathological circular cause chains.