coleam00/Archon · error · Error

buildMessage(nodeOutput) (dynamic caller-supplied message ab

Error message

buildMessage(nodeOutput) (dynamic caller-supplied message about a failed producer)

What it means

assertProducerNotFailed throws a plain Error when a NodeOutput being consumed has state 'failed'. It centralizes the 'a producer node failed, so its output cannot be read' invariant for output-ref resolution; callers supply buildMessage so the thrown message describes the specific failed producer and the consuming site.

Source

Thrown at packages/workflows/src/output-ref.ts:426

 * iteration's real, often-valid-JSON output text, which must never be read as if the
 * producer had succeeded. Mirrors the `state === 'failed'` guard already built into
 * `resolveNodeOutputField` above for the fielded form, so every whole-text reader
 * routes through this one function instead of repeating the check (#2722), replacing
 * the KEEP-IN-SYNC enumeration this module doc used to carry. This is a runtime check,
 * not a type-level one — nothing stops a future caller from reading `nodeOutput.output`
 * directly without calling this function first; the value is having one place to route
 * through, not a compiler-enforced guarantee against bypass.
 *
 * `buildMessage` lets each caller keep its own wording — a binding directive names
 * `if_skipped`, a `when:` guard names the condition, and so on — only the
 * check-and-throw mechanism is shared.
 */
export function assertProducerNotFailed(
  nodeOutput: NodeOutput,
  buildMessage: (failed: Extract<NodeOutput, { state: 'failed' }>) => string
): void {
  if (nodeOutput.state === 'failed') {
    throw new Error(buildMessage(nodeOutput));
  }
}

View on GitHub (pinned to 0773b97458)

Solutions

  1. Inspect the referenced producer node's failure (its error, logs, exit status) and fix the upstream step so it succeeds
  2. Add a retry policy to the producer node if the failure is transient
  3. Gate the consuming node with a condition/when so it does not run after a producer failure, or supply a fallback default for the ref
  4. If the failure is expected, make the producer emit a structured failed-but-handled state instead of relying on the ref to fail

Example fix

// before: downstream always reads upstream output
const out = resolveOutputRef(refs.steps.build, binding);
// after: guard the consumer on producer state
const out = refs.steps.build.state === 'failed'
  ? fallbackValue
  : resolveOutputRef(refs.steps.build, binding);
Defensive patterns

Strategy: try-catch

Validate before calling

// check producer state before resolving
if (nodeOutput.state === 'failed') {
  throw new Error(`producer failed: ${nodeOutput.error ?? 'unknown'}`);
}

Type guard

function producerFailed(out: NodeOutput): out is Extract<NodeOutput, { state: 'failed' }> {
  return out.state === 'failed';
}

Try / catch

try {
  const value = resolveOutputRef(nodeOutput, binding);
} catch (err) {
  log.warn({ err }, 'producer_output_unavailable');
  const value = fallbackValue; // explicit, documented fallback
}

Prevention

When it happens

Trigger: Resolving a workflow output reference (resolveOutputRef), computing the whole-ref logical value (wholeRefLogicalValue), resolving a binding directive, or substituting ${node.output} style references, when the referenced node's NodeOutput.state === 'failed'.

Common situations: A downstream step references an upstream step's output, but the upstream step crashed, exited non-zero, or its agent run failed; the workflow author then sees a resolution error instead of undefined data.

Related errors


AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01). Data as JSON: /api/errors/47503db97b9fb71e. Report an issue: GitHub.