{"record":{"id":"47503db97b9fb71e","repo":"coleam00/Archon","slug":"buildmessage-nodeoutput-dynamic-caller-supplied","errorCode":null,"errorMessage":"buildMessage(nodeOutput) (dynamic caller-supplied message about a failed producer)","messagePattern":"buildMessage\\(nodeOutput\\) \\(dynamic caller-supplied message about a failed producer\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/workflows/src/output-ref.ts","lineNumber":426,"sourceCode":" * iteration's real, often-valid-JSON output text, which must never be read as if the\n * producer had succeeded. Mirrors the `state === 'failed'` guard already built into\n * `resolveNodeOutputField` above for the fielded form, so every whole-text reader\n * routes through this one function instead of repeating the check (#2722), replacing\n * the KEEP-IN-SYNC enumeration this module doc used to carry. This is a runtime check,\n * not a type-level one — nothing stops a future caller from reading `nodeOutput.output`\n * directly without calling this function first; the value is having one place to route\n * through, not a compiler-enforced guarantee against bypass.\n *\n * `buildMessage` lets each caller keep its own wording — a binding directive names\n * `if_skipped`, a `when:` guard names the condition, and so on — only the\n * check-and-throw mechanism is shared.\n */\nexport function assertProducerNotFailed(\n  nodeOutput: NodeOutput,\n  buildMessage: (failed: Extract<NodeOutput, { state: 'failed' }>) => string\n): void {\n  if (nodeOutput.state === 'failed') {\n    throw new Error(buildMessage(nodeOutput));\n  }\n}\n","sourceCodeStart":408,"sourceCodeEnd":429,"githubUrl":"https://github.com/coleam00/Archon/blob/0773b9745896ef0612e709c80845a0f7db315b19/packages/workflows/src/output-ref.ts#L408-L429","documentation":"assertProducerNotFailed throws a plain Error when a NodeOutput being consumed has state 'failed'. It centralizes the 'a producer node failed, so its output cannot be read' invariant for output-ref resolution; callers supply buildMessage so the thrown message describes the specific failed producer and the consuming site.","triggerScenarios":"Resolving a workflow output reference (resolveOutputRef), computing the whole-ref logical value (wholeRefLogicalValue), resolving a binding directive, or substituting ${node.output} style references, when the referenced node's NodeOutput.state === 'failed'.","commonSituations":"A downstream step references an upstream step's output, but the upstream step crashed, exited non-zero, or its agent run failed; the workflow author then sees a resolution error instead of undefined data.","solutions":["Inspect the referenced producer node's failure (its error, logs, exit status) and fix the upstream step so it succeeds","Add a retry policy to the producer node if the failure is transient","Gate the consuming node with a condition/when so it does not run after a producer failure, or supply a fallback default for the ref","If the failure is expected, make the producer emit a structured failed-but-handled state instead of relying on the ref to fail"],"exampleFix":"// before: downstream always reads upstream output\nconst out = resolveOutputRef(refs.steps.build, binding);\n// after: guard the consumer on producer state\nconst out = refs.steps.build.state === 'failed'\n  ? fallbackValue\n  : resolveOutputRef(refs.steps.build, binding);","handlingStrategy":"try-catch","validationCode":"// check producer state before resolving\nif (nodeOutput.state === 'failed') {\n  throw new Error(`producer failed: ${nodeOutput.error ?? 'unknown'}`);\n}","typeGuard":"function producerFailed(out: NodeOutput): out is Extract<NodeOutput, { state: 'failed' }> {\n  return out.state === 'failed';\n}","tryCatchPattern":"try {\n  const value = resolveOutputRef(nodeOutput, binding);\n} catch (err) {\n  log.warn({ err }, 'producer_output_unavailable');\n  const value = fallbackValue; // explicit, documented fallback\n}","preventionTips":["Add retry policies to producer nodes whose failures are transient","Gate consumers on producer success instead of unconditionally reading refs","Check node state before dereferencing outputs in scripts","Keep producer steps small so failures are diagnosable quickly"],"tags":["workflow","output-reference","failed-producer","runtime"],"backgroundTag":"failed-dependency-output-reference","analyzedSha":"0773b9745896ef0612e709c80845a0f7db315b19","analyzedAt":"2026-09-01T02:28:07.064Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}