coleam00/Archon · error
Node '${consumerId}' binding '${name}': 'from' must be exact
Error message
Node '${consumerId}' binding '${name}': 'from' must be exactly one whole '$node.output' or '$node.output.field' reference, got '${directive.from}'. What it means
A binding directive's from field must parse as exactly one whole output reference — '$node.output' or '$node.output.field' — via parseWholeOutputRef. Anything else (interpolated text, multiple refs, wrong syntax like $node.result or node.output without $) fails here. The directive form deliberately does not support template splicing; use a plain string value for that.
Source
Thrown at packages/workflows/src/dag-executor.ts:475
`Node '${consumerId}' binding '${name}': an object value must be a binding directive ` +
"{ from: '$node.output[.field]', if_skipped?: <value> }. Use a string, number, " +
'boolean, null, or array for a literal value.'
);
}
resolved[name] = resolveWorkflowValue(rawValue, ctx, runInputs, true);
}
return resolved;
}
function resolveBindingDirective(
consumerId: string,
name: string,
directive: BindingDirective,
ctx: ShellInputContext
): JsonValue {
const ref = parseWholeOutputRef(directive.from);
if (ref === undefined) {
throw new Error(
`Node '${consumerId}' binding '${name}': 'from' must be exactly one whole ` +
`'$node.output' or '$node.output.field' reference, got '${directive.from}'.`
);
}
const producer = ctx.nodeOutputs.get(ref.nodeId);
if (producer === undefined || producer.state === 'skipped' || producer.state === 'pending') {
// Presence-keyed: `if_skipped: null` (or false/0/'') is a real declared default.
if (Object.hasOwn(directive, 'if_skipped')) return directive.if_skipped as JsonValue;
throw new Error(
`Node '${consumerId}' binding '${name}' reads '${directive.from}', but node ` +
`'${ref.nodeId}' did not run (skipped or pending), so it has no output to read. ` +
"Declare 'if_skipped:' on the binding to supply a default for that branch, or " +
`guard '${consumerId}' with a 'when:' condition.`
);
}
// A failed producer never falls back to `if_skipped` (#2696): that default exists for
// a branch that legitimately didn't run, not for a run that ran and produced a result
// that can't be trusted (a loop_group's failure paths carry the last completedView on GitHub (pinned to 0773b97458)
Solutions
- Set from: to exactly one '$node.output' or '$node.output.field'.
- Move literal text/interpolation into the node body (bash:/script:/prompt:) or a downstream template instead of the binding.
- For run inputs, note $INPUTS refs are resolved by resolveWorkflowValue, not by binding directives — use a plain string value for those.
Example fix
// before
with:
msg:
from: 'Result: $step1.output'
// after
with:
msg:
from: '$step1.output' # literal text goes in the command/prompt body Defensive patterns
Strategy: validation
Validate before calling
const WHOLE_REF = /^\$[A-Za-z0-9_-]+\.output(\.[A-Za-z0-9_-]+)?$/;
function validateFrom(from: string): string | null {
return WHOLE_REF.test(from) ? null : `'from' must be '$node.output' or '$node.output.field', got '${from}'`;
} Try / catch
try {
runWorkflow(wf);
} catch (e) {
if (e instanceof Error && e.message.includes("'from' must be exactly one whole")) {
console.error('Malformed binding directive:', e.message);
} else throw e;
} Prevention
- Keep from: to a single pure ref — no prose, no concatenation, no multiple refs.
- Move any literal text or interpolation into the node body, not the binding.
- Type the directive in code as { from: `$${string}.output${string}` } where possible.
When it happens
Trigger: resolveBindingDirective called with directive.from that parseWholeOutputRef rejects: e.g. 'prefix $a.output suffix', '$a.output.deeply.nested.path' if unsupported, '$INPUTS.x', 'a.output' missing '$', or an empty string.
Common situations: Trying to concatenate a node output with literal text inside from:; mixing two refs in one from:; authoring the directive programmatically with a template string; copying prompt-style syntax ({{node.output}}) into the directive.
Related errors
- Node '${consumerId}' binding '${name}': an object value must
- Invalid --status '${opts.status}'. Valid: ${workflowRunStatu
- Cannot signal a non-event workflow wait
- Run ${run.id}'s gate ('${approval.type}') only accepts 'appr
- Run ${run.id}'s gate only accepts 'approve' or 'reject' — '$
AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01).
Data as JSON: /api/errors/528ec6e79db7c05e.
Report an issue: GitHub.