coleam00/Archon · error · Error
Unknown input '$INPUTS.${name}'.${suffix}
Error message
Unknown input '$INPUTS.${name}'.${suffix} What it means
substituteInputRefs replaces `$INPUTS.<name>` references in node bodies with declared run inputs. It throws when the referenced input name is not declared, appending either a closest-match 'Did you mean' hint or the list of available inputs (or a note that the run declares none).
Source
Thrown at packages/workflows/src/output-ref.ts:173
}
/** Resolve every runtime `$INPUTS.<name>` reference in a text surface. */
export function substituteInputRefs(
text: string,
inputs: Record<string, JsonValue> | undefined
): string {
const pattern = new RegExp(String.raw`\$INPUTS\.(${INPUT_NAME_SOURCE})`, 'g');
return text.replace(pattern, (_match, name: string) => {
if (inputs && Object.hasOwn(inputs, name)) return canonicalValueText(inputs[name]);
const known = inputs ? Object.keys(inputs) : [];
const hint = similarNodeIds(name, known);
const suffix =
hint.length > 0
? ` Did you mean ${hint.map(candidate => `$INPUTS.${candidate}`).join(', ')}?`
: known.length > 0
? ` Available inputs: ${known.map(candidate => `$INPUTS.${candidate}`).join(', ')}.`
: ' This run has no declared inputs.';
throw new Error(`Unknown input '$INPUTS.${name}'.${suffix}`);
});
}
/** Anchored whole-value form: the ENTIRE (trimmed) string is one `$id.output[.field]` ref. */
const WHOLE_OUTPUT_REF_PATTERN = new RegExp(
`^${OUTPUT_REF_SOURCE}(?:\\.([a-zA-Z_][a-zA-Z0-9_]*))?$`
);
/**
* Parse a string that is exactly one whole `$node.output[.field]` reference
* (after trimming), or undefined when it is anything else — a literal, a
* template with surrounding text, or not a ref at all. This is what lets a
* binding value distinguish "pass the logical value through" from "splice text
* into a template" without inventing a second ref grammar.
*/
export function parseWholeOutputRef(text: string): { nodeId: string; field?: string } | undefined {
const m = WHOLE_OUTPUT_REF_PATTERN.exec(text.trim());
if (!m) return undefined;View on GitHub (pinned to 0773b97458)
Solutions
- Declare the missing input in the workflow's `inputs:` block.
- Or fix the reference spelling to a declared input (use the 'Did you mean'/Available inputs hint in the message).
- Or remove the `$INPUTS.` reference and pass the value another way (node body literal or producer output ref).
Example fix
// before
inputs: []
node: echo '$INPUTS.target'
// after
inputs:
- name: target
type: string Defensive patterns
Strategy: validation
Validate before calling
function assertInputsReferenced(workflow: Workflow): void {
const declared = new Set(workflow.inputs?.map(i => i.name));
const body = JSON.stringify(workflow.nodes);
for (const m of body.matchAll(/\$INPUTS\.([a-zA-Z_][a-zA-Z0-9_]*)/g)) {
if (!declared.has(m[1])) throw new Error(`Node body references undeclared input $INPUTS.${m[1]}`);
}
} Type guard
function referencesDeclaredInput(workflow: Workflow, name: string): boolean {
return (workflow.inputs ?? []).some(i => i.name === name);
} Try / catch
try {
const body = substituteInputRefs(node.body, inputs);
} catch (err) {
if ((err as Error).message.includes('Unknown input')) {
// message lists 'Did you mean' candidates — surface to the author
console.error(err.message);
} else throw err;
} Prevention
- Keep `inputs:` declarations adjacent to the nodes that consume them and review both together.
- Rename inputs with a repo-wide search of `$INPUTS.<old>` occurrences.
- Add a lint/static check that every `$INPUTS.x` matches a declared input.
- Run a dry-run/validation pass on workflows after editing inputs.
When it happens
Trigger: A node body contains `$INPUTS.foo` while the workflow's `inputs:` declaration has no `foo` (typo, renamed input, or the workflow declares no inputs at all).
Common situations: Renaming an input in `inputs:` without updating node bodies; copying a node from another workflow with different input names; running a workflow whose inputs section was deleted.
Related errors
- 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' — '$
- Run ${run.id}'s gate does not declare decision '${decision}'
AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01).
Data as JSON: /api/errors/a0acabd1f5e5e050.
Report an issue: GitHub.