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

  1. Resubmit the section with only labels listed in the error message's 'Resubmit with one of the schema's labels' hint
  2. Re-read the task's output schema and map the payload to the declared section names
  3. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/f4a109929cb5cfb3. Report an issue: GitHub.