coleam00/Archon · error · OutputRefError

'${ref}' references node '${nodeId}', but no node with that

Error message

'${ref}' references node '${nodeId}', but no node with that id has produced output at this point — the id is either unknown (a typo) or belongs to a node that has not run before this reference.${hint} Fix the id, or ensure '${nodeId}' runs first (e.g. add it to depends_on).

What it means

resolveWorkflowValue resolves a string like '$node.output.field' to an upstream node's logical output. When the referenced nodeId has no entry in the run's nodeOutputs map at resolution time, and the ref targets a specific field, the executor throws an OutputRefError with reason 'unknown-node' plus similar-id suggestions. The library throws it because a field-level reference cannot be resolved lazily — the producer either doesn't exist or hasn't run yet.

Source

Thrown at packages/workflows/src/dag-executor.ts:388

    // Same loud posture (and hint shape) as the text splice in executor-shared.
    const known = runInputs ? Object.keys(runInputs) : [];
    const hint = similarNodeIds(name, known);
    const suffix =
      hint.length > 0
        ? ` Did you mean ${hint.map(h => `$INPUTS.${h}`).join(', ')}?`
        : known.length > 0
          ? ` Available inputs: ${known.map(k => `$INPUTS.${k}`).join(', ')}.`
          : ' This run has no declared inputs.';
    throw new Error(`Unknown input '$INPUTS.${name}'.${suffix}`);
  }
  const wholeRef = parseWholeOutputRef(rawValue);
  if (wholeRef !== undefined) {
    const producer = ctx.nodeOutputs.get(wholeRef.nodeId);
    if (producer !== undefined) {
      return wholeRefLogicalValue(producer, wholeRef.nodeId, wholeRef.field);
    }
    if (wholeRef.field !== undefined) {
      throw new OutputRefError(
        wholeRef.nodeId,
        wholeRef.field,
        'unknown-node',
        similarNodeIds(wholeRef.nodeId, ctx.nodeOutputs.keys())
      );
    }
    if (strictWholeRef) {
      const candidates = similarNodeIds(wholeRef.nodeId, ctx.nodeOutputs.keys());
      const hint =
        candidates.length > 0 ? ` Did you mean: ${candidates.map(c => `'${c}'`).join(', ')}?` : '';
      throw new Error(
        `Binding value '$${wholeRef.nodeId}.output' references node '${wholeRef.nodeId}', ` +
          'but no node with that id has produced output at this point — the id is either ' +
          'unknown (a typo) or belongs to a node that has not run before this reference.' +
          `${hint} Fix the id, or add '${wholeRef.nodeId}' to depends_on.`
      );
    }
    // Lenient legacy surface: fall through to the template path, which resolves the

View on GitHub (pinned to 0773b97458)

Solutions

  1. Fix the node id in the reference (check the 'Did you mean' candidates in the error hint).
  2. Add the producer to the consumer's depends_on so its output exists before binding resolution.
  3. If the producer is on a possibly-skipped branch, use a binding directive { from: '$node.output.field', if_skipped: <default> } instead of a bare string.

Example fix

// before
with:
  report: '$analisis.output.summary'   # typo'd producer
// after
with:
  report: '$analysis.output.summary'
depends_on: [analysis]
Defensive patterns

Strategy: validation

Validate before calling

function validateFieldRef(ref: string, knownNodeIds: Set<string>): string | null {
  const m = /^\$([A-Za-z0-9_-]+)\.output\.([A-Za-z0-9_-]+)$/.exec(ref);
  if (!m) return null; // not a whole field ref; other validation applies
  return knownNodeIds.has(m[1]) ? null : `Unknown node id '${m[1]}' in '${ref}'`;
}

Try / catch

try {
  runWorkflow(wf);
} catch (e) {
  if (e instanceof OutputRefError && e.reason === 'unknown-node') {
    console.error(`Bad node ref '${e.nodeId}' (field '${e.field}'). Did you mean: ${e.similar.join(', ')}?`);
  } else throw e;
}

Prevention

When it happens

Trigger: Resolving a 'with:' binding or node value whose string is exactly '$producer.output.field' (parseWholeOutputRef matched, field is defined) while ctx.nodeOutputs has no entry for the producer id — e.g. a typo'd node id, or the producer is not in depends_on and executes after the consumer.

Common situations: Renaming a node in YAML without updating downstream $refs; forgetting to list the producer in depends_on so it hasn't run when the consumer's bindings resolve; programmatically-built workflow definitions bypassing loader validation; referencing a node in a different branch guarded by when:.

Related errors


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