can1357/oh-my-pi · error
Section ${formatYieldLabels(yieldType as string[])} uses unk
Error message
Section ${formatYieldLabels(yieldType as string[])} uses unknown incremental yield label(s): ${formatYieldLabels(unknownLabels)}. Resubmit with one of the schema's labels: ${validLabels}. What it means
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.
Source
Thrown at packages/coding-agent/src/tools/yield.ts:420
const remaining = MAX_EMPTY_RESULT_RETRIES - this.#emptyResultFailures;
throw new Error(
`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}.`,
);
}
const status = errorMessage !== undefined ? "aborted" : "success";
let schemaValidationOverridden = false;
// Unknown incremental labels are a hard contract mismatch with the closed caller
// schema. Reject before the last-turn short-circuit too: `type: ["findings"], result: {}`
// would otherwise be accepted as a typed last-turn incremental yield, then a sibling
// section's MAX_SCHEMA_RETRIES override flips schemaOverridden in finalization and the
// stale section rides along untouched.
if (status === "success" && isIncremental) {
const unknownLabels = this.#unknownIncrementalLabels(yieldType as string[]);
if (unknownLabels.length > 0) {
const validLabels =
this.#knownSectionLabels.length > 0 ? formatYieldLabels(this.#knownSectionLabels) : "none";
throw new Error(
`Section ${formatYieldLabels(yieldType as string[])} uses unknown incremental yield label(s): ${formatYieldLabels(unknownLabels)}. Resubmit with one of the schema's labels: ${validLabels}.`,
);
}
}
// A schema-bound terminal last-turn yield with no accumulated sections can
// only assemble raw prose, which finalization then rejects post-mortem as a
// fatal schema_violation the child can no longer correct. Catch it here as
// a retryable error instead. With sections present, a data-less finalize
// legitimately closes the incremental flow (assembly keeps the sections).
if (status === "success" && useLastTurn && !isIncremental && this.#validate && !this.#hasIncrementalSections) {
throw new Error(
"This task requires structured output matching the declared schema; a last-turn result cannot satisfy it. " +
`Submit the full object: {"result":{"data":<object matching the schema>}}.`,
);
}
if (status === "success" && !useLastTurn) {
if (data === null) {
throw new Error("data is required when yield indicates success");View on GitHub (pinned to 9690622007)
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
Example fix
// before
yield({ result: { type: ["finding"], data: { text: "..." } } });
// after
yield({ result: { type: ["findings"], data: { text: "..." } } }); Defensive patterns
Strategy: validation
Validate before calling
const validLabels = new Set(getSchemaSectionLabels());
if (Array.isArray(type) && type.some(t => !validLabels.has(t))) {
throw new TypeError(`unknown section labels: ${type.filter(t => !validLabels.has(t))}`);
} Type guard
function labelsAreKnown(type, known) {
return Array.isArray(type) && type.every(t => known.includes(t));
} Try / catch
try {
yield({ result: { type, data } });
} catch (err) {
const m = err.message.match(/schema's labels: (.+)\./);
if (m) {
yield({ result: { type: [m[1].split(',')[0].trim()], data } });
} else throw err;
} Prevention
- 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
When it happens
Trigger: 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"].
Common situations: 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.
Related errors
- This task requires structured output matching the declared s
- result cannot contain both data and error
- result must contain either \`data\` or \`error\`. Use \`{res
- data is required when yield indicates success
- ${scope} does not match schema: ${formatAllValidationIssues(
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/f4a109929cb5cfb3.
Report an issue: GitHub.