coleam00/Archon · error · OutputRefError
not-in-schema
not-in-schema
Error message
not-in-schema
What it means
For a producer that declares an output schema (`output_format` with a `properties` map), the declared field set IS the contract: referencing a field not in the declared schema throws immediately. This catches the author early — the referenced field can never appear, even if the producer emits extra keys.
Source
Thrown at packages/workflows/src/output-ref.ts:361
}
// A failed producer never resolves a field, however JSON-shaped its leftover
// output looks (#2713): a loop_group's failure paths carry the last completed
// iteration's real, often-valid-JSON text, which would otherwise be read here
// as if the group had succeeded — the same class of bug #2696/#2710 fixed for
// the `{ from, if_skipped }` binding directive.
if (nodeOutput.state === 'failed') {
throw new OutputRefError(nodeId, field, 'producer-failed');
}
const declaredFields = 'declaredFields' in nodeOutput ? nodeOutput.declaredFields : undefined;
const structured = 'structuredOutput' in nodeOutput ? nodeOutput.structuredOutput : undefined;
const structuredObj = asPlainObject(structured);
// 1. Declared-schema producer — the declared property set IS the contract.
if (declaredFields !== undefined) {
if (!declaredFields.includes(field)) {
throw new OutputRefError(nodeId, field, 'not-in-schema');
}
// Prefer the parsed payload; fall back to parsing the JSON-serialized output.
// The fallback covers older NodeOutput rows that predate `structuredOutput`,
// and resumes of runs persisted before `structured_output` rode along in
// `node_completed` events (#2637) — current resumes rehydrate the payload.
const obj = structuredObj ?? parseOutputObject(nodeOutput.output);
// No parseable object AT ALL is not a declared-optional field — it is a producer
// that did not honour its schema, and it must fail exactly as loudly as the
// schemaless path below (#2456). Returning empty here made declaring
// `output_format` QUIETER than declaring nothing, which is backwards: a
// `workflow:` node's output_format is never validated against the child (it only
// populates declaredFields), so every declared field silently became ''.
if (obj === undefined) {
throw new OutputRefError(nodeId, field, unparseableReason(nodeOutput.output));
}
const value = obj[field];
// Required fields are guaranteed present (the producer validated post-parse),
// so a missing/explicit-null value here is a declared-optional field → empty.View on GitHub (pinned to 0773b97458)
Solutions
- Add `fieldName` to the producer's `output_format.properties` if the producer should emit it.
- Or correct the consumer's `$producer.field` reference to a declared field name.
- Or drop the `output_format` declaration (making the producer schemaless) only if untyped access is truly intended — this loses validation.
Example fix
// before
output_format:
properties:
summary: {type: string}
// after
output_format:
properties:
summary: {type: string}
score: {type: number} Defensive patterns
Strategy: validation
Validate before calling
function assertFieldDeclared(producer: { output_format?: Record<string, unknown> }, field: string): void {
const props = producer.output_format?.properties as Record<string, unknown> | undefined;
if (props && !(field in props)) {
throw new Error(`$producer.${field} is not declared in output_format properties: ${Object.keys(props).join(', ')}`);
}
} Type guard
function isDeclaredField(schema: { properties?: Record<string, unknown> }, field: string): field is keyof schema['properties'] {
return schema.properties !== undefined && field in schema.properties;
} Try / catch
try {
const { value } = resolveNodeOutputField(nodeOutput, nodeId, field);
} catch (err) {
if (err instanceof OutputRefError && err.reason === 'not-in-schema') {
console.error(`${field} missing from producer's declared output_format; fix schema or reference`);
} else throw err;
} Prevention
- Change producer schema and consumer references in the same commit; grep for `$producer.` refs.
- Keep output_format.properties as the single source of truth for consumer-facing fields.
- Add a lint that cross-checks `$node.field` refs against producers' declared fields.
- Avoid adding consumer refs to fields the producer only emits informally.
When it happens
Trigger: A consumer references `$producer.fieldName` where producer declares `output_format.properties` without `fieldName` (typo, renamed schema property, schema tightened after the consumer was written).
Common situations: Renaming a property in the producer's output_format without updating consumers; AI node schema updated to a subset; copied consumer code referencing fields from a different producer.
Related errors
- outcomeDeclarationError (workflow outcome declaration valida
- producer-not-run
- producer-failed
- unparseableReason(nodeOutput.output) (dynamic reason code fo
- missing-key
AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01).
Data as JSON: /api/errors/55c1a352ec081e9c.
Report an issue: GitHub.