KeygraphHQ/shannon · critical · PipelineExecutionError

Pipeline failed

Error message

Pipeline failed

What it means

PipelineExecutionError is the terminal signal thrown by the pentestPipeline Temporal workflow when any unhandled, non-cancellation error escapes the pipeline body. It wraps state.error (or the fallback string 'Pipeline failed') and carries the populated PipelineState (real agentMetrics, completedAgents, summary) plus the original error as cause, so consumers can report actual spend rather than a zeroed failed state. It is thrown only after the workflow finalizes via logWorkflowComplete (which is itself shielded in a try/catch so finalization never blocks the throw).

Source

Thrown at apps/worker/src/temporal/workflows.ts:710

    state.error = formatWorkflowError(error, state.currentPhase, state.currentAgent);
    const errorCode = classifyErrorCode(error);
    if (errorCode) {
      state.errorCode = errorCode;
    }
    state.summary = computeSummary(state);

    // Log workflow failure summary
    try {
      await a.logWorkflowComplete(activityInput, toWorkflowSummary(state, 'failed'));
    } catch (completionError) {
      log.warn('Failed to finalize failed workflow', {
        error: completionError instanceof Error ? completionError.message : String(completionError),
      });
    }

    // Carry the populated state so a consumer can report real spend instead of a zeroed
    // failed state. The original error rides as `cause` for classification/reporting.
    throw new PipelineExecutionError(state.error ?? 'Pipeline failed', state, { cause: error });
  }
}

/** OSS workflow entry point — thin shell around the extracted pipeline function. */
export async function pentestPipelineWorkflow(input: PipelineInput): Promise<PipelineState> {
  return pentestPipeline(input);
}

View on GitHub (pinned to 1ae0a142f8)

Solutions

  1. Inspect the thrown PipelineExecutionError.cause and error.state.errorCode/state.error to find the root failure (this is a wrapper, not the root cause).
  2. Match state.currentPhase and state.currentAgent/state.failedAgent to localize which step failed.
  3. Address the underlying error (e.g. clear a git lock, fix a config, free disk) using the specific error's guidance, then resume the workspace.
  4. If state.errorCode indicates a non-retryable config/prompt error, correct the input and start a new run.
  5. Resume with the same workspace name once the root cause is resolved: completed agents are skipped and only the failed phase re-runs.
  6. Check the workflow.log in <workspace>/.shannon/ for the full failure context around state.currentAgent.

Example fix

// before: underlying agent error surfaces only as generic 'Pipeline failed'
//   try { await client.execute(pentestPipelineWorkflow, input) }
//   catch (e) { console.log(e.message) }  // 'Pipeline failed'
// after: unwrap cause and state for actionable detail
//   catch (e) {
//     if (e instanceof PipelineExecutionError) {
//       console.log(e.state.currentPhase, e.state.failedAgent, e.state.errorCode);
//       console.log(e.cause);  // the real error
//     }
//   }
Defensive patterns

Strategy: try-catch

Validate before calling

// Before the workflow, run preflight checks that cover the most common root causes
await preflight(input); // validates model credential, repo path, config schema, prompt existence
// and ensure disk + git repo health so checkpoint/report activities will not fail mid-pipeline

Type guard

function isPipelineExecutionError(e: unknown): e is PipelineExecutionError {
  return e instanceof PipelineExecutionError && e.name === 'PipelineExecutionError';
}

Try / catch

try {
  const state = await client.execute(pentestPipelineWorkflow, input);
  return state;
} catch (e) {
  if (e instanceof PipelineExecutionError) {
    // this is a wrapper — diagnose e.cause, e.state.errorCode, e.state.failedAgent, e.state.currentPhase
    log.error('pipeline failed', {
      phase: e.state.currentPhase, agent: e.state.failedAgent,
      code: e.state.errorCode, cause: e.cause,
    });
    // fix the root cause (per its specific error), then resume the same workspace
  }
  throw e;
}

Prevention

When it happens

Trigger: Any activity or workflow step inside pentestPipeline throws a non-cancellation error that is not caught earlier: a PentestError from an agent activity (e.g. GIT_CHECKPOINT_FAILED, DELIVERABLE_NOT_FOUND, a prompt load failure), a Temporal ApplicationFailure, or an unexpected exception. The top-level catch sets state.status='failed', computes the error code and summary, finalizes, and re-throws as PipelineExecutionError with the original as cause.

Common situations: An agent exhausts its retries (3 attempts) and the activity error propagates up. A checkpoint or deliverable operation fails (errors 40/48/49/50). A prompt/config error (41-47) during a phase. A provider/credentials failure that is non-retryable. Disk-full or permission errors during report assembly. The cause field holds the specific underlying error to diagnose.

Related errors


AI-assisted analysis of KeygraphHQ/shannon@1ae0a142f8 (2026-08-12). Data as JSON: /api/errors/69da9dc3f300aca8. Report an issue: GitHub.