{"record":{"id":"f4a109929cb5cfb3","repo":"can1357/oh-my-pi","slug":"section-formatyieldlabels-yieldtype-as-string","errorCode":null,"errorMessage":"Section ${formatYieldLabels(yieldType as string[])} uses unknown incremental yield label(s): ${formatYieldLabels(unknownLabels)}. Resubmit with one of the schema's labels: ${validLabels}.","messagePattern":"Section (.+?) uses unknown incremental yield label\\(s\\): (.+?)\\. Resubmit with one of the schema's labels: (.+?)\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/yield.ts","lineNumber":420,"sourceCode":"\t\t\tconst remaining = MAX_EMPTY_RESULT_RETRIES - this.#emptyResultFailures;\n\t\t\tthrow new Error(\n\t\t\t\t`result must contain either \\`data\\` or \\`error\\`. Use \\`{result: {data: <your output>}}\\` for success or \\`{result: {error: \"message\"}}\\` for failure. Empty untyped result retries remaining before abort: ${remaining}.`,\n\t\t\t);\n\t\t}\n\n\t\tconst status = errorMessage !== undefined ? \"aborted\" : \"success\";\n\t\tlet schemaValidationOverridden = false;\n\t\t// Unknown incremental labels are a hard contract mismatch with the closed caller\n\t\t// schema. Reject before the last-turn short-circuit too: `type: [\"findings\"], result: {}`\n\t\t// would otherwise be accepted as a typed last-turn incremental yield, then a sibling\n\t\t// section's MAX_SCHEMA_RETRIES override flips schemaOverridden in finalization and the\n\t\t// stale section rides along untouched.\n\t\tif (status === \"success\" && isIncremental) {\n\t\t\tconst unknownLabels = this.#unknownIncrementalLabels(yieldType as string[]);\n\t\t\tif (unknownLabels.length > 0) {\n\t\t\t\tconst validLabels =\n\t\t\t\t\tthis.#knownSectionLabels.length > 0 ? formatYieldLabels(this.#knownSectionLabels) : \"none\";\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Section ${formatYieldLabels(yieldType as string[])} uses unknown incremental yield label(s): ${formatYieldLabels(unknownLabels)}. Resubmit with one of the schema's labels: ${validLabels}.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\t// A schema-bound terminal last-turn yield with no accumulated sections can\n\t\t// only assemble raw prose, which finalization then rejects post-mortem as a\n\t\t// fatal schema_violation the child can no longer correct. Catch it here as\n\t\t// a retryable error instead. With sections present, a data-less finalize\n\t\t// legitimately closes the incremental flow (assembly keeps the sections).\n\t\tif (status === \"success\" && useLastTurn && !isIncremental && this.#validate && !this.#hasIncrementalSections) {\n\t\t\tthrow new Error(\n\t\t\t\t\"This task requires structured output matching the declared schema; a last-turn result cannot satisfy it. \" +\n\t\t\t\t\t`Submit the full object: {\"result\":{\"data\":<object matching the schema>}}.`,\n\t\t\t);\n\t\t}\n\t\tif (status === \"success\" && !useLastTurn) {\n\t\t\tif (data === null) {\n\t\t\t\tthrow new Error(\"data is required when yield indicates success\");","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/yield.ts#L402-L438","documentation":"Incremental (array-typed) section yields must use labels declared by the task's output schema. When a successful incremental section references label(s) that the schema does not define, the yield tool throws, listing the unknown labels and the valid ones. This is a contract check so assembled section data still matches the declared schema at finalization.","triggerScenarios":"Calling yield with type as a non-empty string array (incremental section) where one or more labels are not in the task schema's known section labels, e.g. type: [\"finding\"] when the schema only defines [\"findings\",\"notes\"].","commonSituations":"A model invents plausible-but-wrong section names (singular vs plural, synonyms); the task prompt/schema was changed but the agent still uses labels from an older prompt version; a hand-written harness hard-codes labels that drifted from the schema.","solutions":["Resubmit the section with only labels listed in the error message's 'Resubmit with one of the schema's labels' hint","Re-read the task's output schema and map the payload to the declared section names","If the schema genuinely needs the new label, update the task schema rather than the yield call"],"exampleFix":"// before\nyield({ result: { type: [\"finding\"], data: { text: \"...\" } } });\n// after\nyield({ result: { type: [\"findings\"], data: { text: \"...\" } } });","handlingStrategy":"validation","validationCode":"const validLabels = new Set(getSchemaSectionLabels());\nif (Array.isArray(type) && type.some(t => !validLabels.has(t))) {\n  throw new TypeError(`unknown section labels: ${type.filter(t => !validLabels.has(t))}`);\n}","typeGuard":"function labelsAreKnown(type, known) {\n  return Array.isArray(type) && type.every(t => known.includes(t));\n}","tryCatchPattern":"try {\n  yield({ result: { type, data } });\n} catch (err) {\n  const m = err.message.match(/schema's labels: (.+)\\./);\n  if (m) {\n    yield({ result: { type: [m[1].split(',')[0].trim()], data } });\n  } else throw err;\n}","preventionTips":["Derive section labels from the schema definition, never hard-code them","Copy labels verbatim from the task prompt/schema; watch singular/plural forms","After a schema change, re-run any harness with cached label lists"],"tags":["tool-call","yield","schema","labels","subagent"],"backgroundTag":"unknown-enum-value","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}