coleam00/Archon · error · IncludeExpansionError
outcomeDeclarationError (workflow outcome declaration valida
Error message
outcomeDeclarationError (workflow outcome declaration validation message, wrapped in IncludeExpansionError)
What it means
After building the expanded workflow result, the expander runs `validateWorkflowOutcomeDeclaration` and wraps any failure in an `IncludeExpansionError`. This guards the workflow's outcome (`returns:`) declaration: it must be a well-formed declaration and consistent with the nodes/refs that exist after include expansion.
Source
Thrown at packages/workflows/src/include-expander.ts:1293
throw new IncludeExpansionError(structureError);
}
const dedupedRequires = [...new Set(requires)];
const result: WorkflowDefinition = {
...collapsed,
nodes: expanded.nodes,
// `returns:` may name an include directive that no longer exists after flattening.
// Rebind it to the same primary sink used for `$includeId.output`; ordinary node ids
// pass through unchanged. Without this, a nested reusable workflow can finish with a
// dangling return id even though every node-level reference was rewritten correctly.
...(collapsed.returns !== undefined
? { returns: expanded.renameIncludeRef(collapsed.returns) }
: {}),
...(dedupedRequires.length > 0 ? { requires: dedupedRequires } : {}),
};
const outcomeDeclarationError = validateWorkflowOutcomeDeclaration(result);
if (outcomeDeclarationError !== null) {
throw new IncludeExpansionError(outcomeDeclarationError);
}
memo.set(name, result);
return result;
}
for (const name of rawByName.keys()) {
if (memo.has(name)) continue; // already expanded as a dependency of an earlier workflow
try {
expandOne(name, []);
} catch (e) {
if (e instanceof IncludeExpansionError) {
failed.add(name);
errors.push({ filename: name, error: e.message, errorType: 'validation_error' });
} else {
throw e;
}
}
}View on GitHub (pinned to 0773b97458)
Solutions
- Read the wrapped outcomeDeclarationError message — it identifies the offending part of the `returns:` declaration
- Update `returns:` to reference outputs that exist after expansion; use the expander's renameIncludeRef-mapped refs
- Validate the `returns:` block against the workflow outcome schema in isolation
- If the referenced output came from an included workflow that changed, re-pin the ref to the new node/output id
Example fix
# before
returns:
summary: ${nodes.summrize.outputs.report} # typo'd node id
# after
returns:
summary: ${nodes.summarize.outputs.report} Defensive patterns
Strategy: validation
Validate before calling
// Check that every node ref in returns: exists in the workflow's nodes.
function validateReturnRefs(wf: { nodes: { id: string }[]; returns?: Record<string, string> }): string[] {
const ids = new Set(wf.nodes.map((n) => n.id));
const bad: string[] = [];
for (const [key, ref] of Object.entries(wf.returns ?? {})) {
const nodeId = ref.match(/^\$?\{?nodes\.([^.]+)\./)?.[1];
if (nodeId && !ids.has(nodeId)) bad.push(`${key} -> ${ref}`);
}
return bad;
} Try / catch
try {
const expanded = expandWorkflowIncludes(rawByName);
} catch (err) {
if (err instanceof IncludeExpansionError) {
throw new Error(`Outcome declaration invalid after expansion: ${err.message}`, { cause: err });
}
throw err;
} Prevention
- Update returns: refs whenever a referenced node's id changes, including across include boundaries
- Rely on the expander's renameIncludeRef mapping instead of hand-writing post-expansion refs
- Schema-check returns: blocks in CI against the workflow outcome schema
- After changing an included workflow, re-expand every parent that includes it
When it happens
Trigger: Calling `expandWorkflowIncludes` where the composed workflow's `returns:` declaration is malformed, references an output path broken by include expansion (e.g. a renamed node ref not remapped), or violates the outcome schema after inlining.
Common situations: A parent declares `returns:` on an output produced by an included node whose id changed, hand-edited `returns:` blocks that no longer match the schema, composition stamping approval gates that changes which outputs are visible.
Related errors
- include target '${name}' not found
- structureError (DAG structure validation message, wrapped in
- workflow.subrun_schema_uncompilable
- Invalid --status '${opts.status}'. Valid: ${workflowRunStatu
- Cannot signal a non-event workflow wait
AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01).
Data as JSON: /api/errors/24b07551c0159cc4.
Report an issue: GitHub.