Problem
In packages/durabletask-js/src/worker/orchestration-executor.ts, the handleEntityOperationFailed method (line 566) creates an EntityOperationFailedException but immediately discards it, only extracting its .message property:
const exception = new EntityOperationFailedException(
pendingCall.entityId,
pendingCall.operationName,
failureDetails,
);
pendingCall.task.fail(exception.message, failedEvent?.getFailuredetails());
CompletableTask.fail() always creates a new generic TaskFailedError, so the EntityOperationFailedException instance (with entity-specific context like entityId, operationName, and structured failureDetails) is lost.
Root Cause
CompletableTask.fail(message, details) unconditionally creates a TaskFailedError. There was no way to pass a pre-constructed exception to the task system, so the handler extracted only the .message string from the EntityOperationFailedException and discarded the rest.
Impact
- API contract violation: The
OrchestrationEntityFeature.callEntity() interface documents @throws {EntityOperationFailedException}, but users actually receive TaskFailedError.
- Lost context: Entity-specific error information (
entityId, operationName, structured failureDetails) is unavailable in catch blocks.
- Dead code: The
EntityOperationFailedException class is exported and has unit tests, but is never actually thrown to user code.
Severity: Medium — Affects all entity operation failure paths in orchestrations. Users relying on instanceof EntityOperationFailedException checks will never match.
Proposed Fix
- Make
EntityOperationFailedException extend TaskFailedError (backward-compatible: existing instanceof TaskFailedError checks still work)
- Add
failWithError() method to CompletableTask for pre-constructed exceptions
- Update
handleEntityOperationFailed to use the EntityOperationFailedException directly
Problem
In
packages/durabletask-js/src/worker/orchestration-executor.ts, thehandleEntityOperationFailedmethod (line 566) creates anEntityOperationFailedExceptionbut immediately discards it, only extracting its.messageproperty:CompletableTask.fail()always creates a new genericTaskFailedError, so theEntityOperationFailedExceptioninstance (with entity-specific context likeentityId,operationName, and structuredfailureDetails) is lost.Root Cause
CompletableTask.fail(message, details)unconditionally creates aTaskFailedError. There was no way to pass a pre-constructed exception to the task system, so the handler extracted only the.messagestring from theEntityOperationFailedExceptionand discarded the rest.Impact
OrchestrationEntityFeature.callEntity()interface documents@throws {EntityOperationFailedException}, but users actually receiveTaskFailedError.entityId,operationName, structuredfailureDetails) is unavailable in catch blocks.EntityOperationFailedExceptionclass is exported and has unit tests, but is never actually thrown to user code.Severity: Medium — Affects all entity operation failure paths in orchestrations. Users relying on
instanceof EntityOperationFailedExceptionchecks will never match.Proposed Fix
EntityOperationFailedExceptionextendTaskFailedError(backward-compatible: existinginstanceof TaskFailedErrorchecks still work)failWithError()method toCompletableTaskfor pre-constructed exceptionshandleEntityOperationFailedto use theEntityOperationFailedExceptiondirectly