Skip to content

[copilot-finds] Bug: setFailed() produces duplicate completion actions when called after setComplete() #237

@github-actions

Description

@github-actions

Problem

RuntimeOrchestrationContext.setFailed() does not remove a previously added completeOrchestrationAction from _pendingActions before adding its own FAILED action. When setFailed() is called after setComplete() has already run (e.g., due to a NonDeterminismError thrown during replay after the generator finishes), the resulting getActions() returns two completeOrchestration actions — one COMPLETED and one FAILED — sent to the sidecar.

File: packages/durabletask-js/src/worker/runtime-orchestration-context.ts, setFailed() method (line ~226)

Root Cause

Both setComplete() and setContinuedAsNew() guard against double-completion with if (this._isComplete) { return; }. setFailed() has no such guard and no cleanup of the previous completion action.

The scenario:

  1. During replay, the generator finishes early (returns without yielding expected actions).
  2. setComplete() is called via StopIterationError, adding a COMPLETED action to _pendingActions.
  3. A subsequent history event fails validation (e.g., handleTaskScheduled can't find its expected pending action), throwing NonDeterminismError.
  4. The outer catch in execute() calls setFailed(error), which adds a SECOND completion action (FAILED) without removing the first.
  5. getActions() returns both, producing an invalid response with two terminal actions.

Proposed Fix

When setFailed() is called and _isComplete is already true, find and remove the existing completeOrchestration action from _pendingActions before adding the FAILED action. This ensures exactly one completion action is returned, correctly reporting the failure.

Impact

Severity: Medium — Only triggers with non-deterministic orchestrator code during replay, but produces an invalid protocol response (duplicate completion actions) that could confuse the sidecar or cause undefined behavior.

Metadata

Metadata

Assignees

No one assigned

    Labels

    copilot-findsFindings from daily automated code review agent

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions