can1357/oh-my-pi · error

This task requires structured output matching the declared s

Error message

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>}}.

What it means

When a schema-bound task reaches its terminal last-turn yield with no accumulated incremental sections, the tool can only assemble raw prose — which finalization would reject post-mortem as a fatal schema_violation the subagent could no longer fix. To keep the failure correctable, execute() throws this retryable error up front, telling the caller to submit a full structured object instead.

Source

Thrown at packages/coding-agent/src/tools/yield.ts:431

		// 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");
			}
			const validateData = (value: unknown): JsonSchemaValidationResult | undefined =>
				isIncremental
					? this.#validateIncrementalSection(yieldType as string[], value)
					: this.#validate
						? this.#validate(value)
						: undefined;
			let sectionFailure = validateData(data);
			if (sectionFailure && !sectionFailure.success && typeof data === "string") {
				// Lossless recovery: a JSON-encoded payload string parses to exactly
				// the intended value (executor finalization already parses terminal

View on GitHub (pinned to 9690622007)

Solutions

  1. Instead of useLastTurn, submit the complete object: {"result":{"data":<object matching the schema>}}
  2. Build the payload field-by-field against the declared JSON schema before yielding
  3. If prose really is intended, switch the task to an unstructured (no-schema) output configuration

Example fix

// before
yield({ result: { useLastTurn: true } });
// after
yield({ result: { data: { summary: "...", findings: [] } } });
Defensive patterns

Strategy: validation

Validate before calling

if (useLastTurn && taskHasOutputSchema && !hasAccumulatedSections()) {
  throw new TypeError('useLastTurn is invalid for schema-bound tasks without sections; submit full data object');
}

Type guard

function canUseLastTurn(result, schemaBound, hasSections) {
  return !(schemaBound && result.useLastTurn === true && !hasSections);
}

Try / catch

try {
  yield({ result: { useLastTurn: true } });
} catch (err) {
  if (err.message.includes('structured output')) {
    yield({ result: { data: assembleSchemaObject() } });
  } else throw err;
}

Prevention

When it happens

Trigger: Calling yield with useLastTurn: true on a task that declares an output schema, while no incremental sections have been accumulated (#hasIncrementalSections is false) and status is success.

Common situations: A model finishes its work and tries to 'let the last message be the result' on a structured-output task; an agent template always sets useLastTurn regardless of whether the task is schema-bound.

Related errors


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