{"record":{"id":"24b07551c0159cc4","repo":"coleam00/Archon","slug":"outcomedeclarationerror-workflow-outcome-declarat","errorCode":null,"errorMessage":"outcomeDeclarationError (workflow outcome declaration validation message, wrapped in IncludeExpansionError)","messagePattern":"outcomeDeclarationError \\(workflow outcome declaration validation message, wrapped in IncludeExpansionError\\)","errorType":"validation","errorClass":"IncludeExpansionError","httpStatus":null,"severity":"error","filePath":"packages/workflows/src/include-expander.ts","lineNumber":1293,"sourceCode":"      throw new IncludeExpansionError(structureError);\n    }\n\n    const dedupedRequires = [...new Set(requires)];\n    const result: WorkflowDefinition = {\n      ...collapsed,\n      nodes: expanded.nodes,\n      // `returns:` may name an include directive that no longer exists after flattening.\n      // Rebind it to the same primary sink used for `$includeId.output`; ordinary node ids\n      // pass through unchanged. Without this, a nested reusable workflow can finish with a\n      // dangling return id even though every node-level reference was rewritten correctly.\n      ...(collapsed.returns !== undefined\n        ? { returns: expanded.renameIncludeRef(collapsed.returns) }\n        : {}),\n      ...(dedupedRequires.length > 0 ? { requires: dedupedRequires } : {}),\n    };\n    const outcomeDeclarationError = validateWorkflowOutcomeDeclaration(result);\n    if (outcomeDeclarationError !== null) {\n      throw new IncludeExpansionError(outcomeDeclarationError);\n    }\n    memo.set(name, result);\n    return result;\n  }\n\n  for (const name of rawByName.keys()) {\n    if (memo.has(name)) continue; // already expanded as a dependency of an earlier workflow\n    try {\n      expandOne(name, []);\n    } catch (e) {\n      if (e instanceof IncludeExpansionError) {\n        failed.add(name);\n        errors.push({ filename: name, error: e.message, errorType: 'validation_error' });\n      } else {\n        throw e;\n      }\n    }\n  }","sourceCodeStart":1275,"sourceCodeEnd":1311,"githubUrl":"https://github.com/coleam00/Archon/blob/0773b9745896ef0612e709c80845a0f7db315b19/packages/workflows/src/include-expander.ts#L1275-L1311","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nreturns:\n  summary: ${nodes.summrize.outputs.report}   # typo'd node id\n# after\nreturns:\n  summary: ${nodes.summarize.outputs.report}","handlingStrategy":"validation","validationCode":"// Check that every node ref in returns: exists in the workflow's nodes.\nfunction validateReturnRefs(wf: { nodes: { id: string }[]; returns?: Record<string, string> }): string[] {\n  const ids = new Set(wf.nodes.map((n) => n.id));\n  const bad: string[] = [];\n  for (const [key, ref] of Object.entries(wf.returns ?? {})) {\n    const nodeId = ref.match(/^\\$?\\{?nodes\\.([^.]+)\\./)?.[1];\n    if (nodeId && !ids.has(nodeId)) bad.push(`${key} -> ${ref}`);\n  }\n  return bad;\n}","typeGuard":null,"tryCatchPattern":"try {\n  const expanded = expandWorkflowIncludes(rawByName);\n} catch (err) {\n  if (err instanceof IncludeExpansionError) {\n    throw new Error(`Outcome declaration invalid after expansion: ${err.message}`, { cause: err });\n  }\n  throw err;\n}","preventionTips":["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"],"tags":["workflow","includes","outcome","validation","schema"],"backgroundTag":"invalid-outcome-declaration","analyzedSha":"0773b9745896ef0612e709c80845a0f7db315b19","analyzedAt":"2026-09-01T02:28:07.064Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}