can1357/oh-my-pi · error
result must be an object containing either data or error. ${
Error message
result must be an object containing either data or error. ${YIELD_RESULT_FORMAT_HINT} What it means
YieldTool.execute requires the top-level `result` parameter to be an object containing at least one of `data` or `error`. resolveResultRecord returns undefined when `result` is missing, not an object, or has neither key, and execute throws this Error with YIELD_RESULT_FORMAT_HINT: submit success as {"result":{"data":<output>}} or failure as {"result":{"error":"message"}}.
Source
Thrown at packages/coding-agent/src/tools/yield.ts:370
this.#rejectUnknownSections = rejectUnknownSections;
this.#knownSectionLabels = knownSectionLabels;
this.#isKnownSection = isKnownSection;
this.description = prompt.render(yieldDescription, { hasOutputSchema: validate !== undefined });
this.parameters = parameters;
}
async execute(
_toolCallId: string,
params: unknown,
_signal?: AbortSignal,
_onUpdate?: AgentToolUpdateCallback<YieldDetails>,
_context?: AgentToolContext,
): Promise<AgentToolResult<YieldDetails>> {
const raw = params as Record<string, unknown>;
const yieldType = parseYieldType(raw.type);
const resultRecord = resolveResultRecord(raw, yieldType);
if (resultRecord === undefined) {
throw new Error(`result must be an object containing either data or error. ${YIELD_RESULT_FORMAT_HINT}`);
}
const errorMessage = typeof resultRecord.error === "string" ? resultRecord.error : undefined;
let data = resultRecord.data;
const useLastTurn =
errorMessage === undefined && data === undefined && yieldType !== undefined && !("error" in resultRecord);
// Incremental array-typed sections carry partial data (one finding, one
// field) that cannot satisfy the full output schema; the assembled result
// is validated as a whole at finalization (executor finalizeSubprocessOutput).
const isIncremental = Array.isArray(yieldType) && yieldType.length > 0;
if (errorMessage !== undefined && data !== undefined) {
throw new Error("result cannot contain both data and error");
}
if (errorMessage === undefined && data === undefined && yieldType === undefined) {
this.#emptyResultFailures++;
if (this.#emptyResultFailures > MAX_EMPTY_RESULT_RETRIES) {
const attemptCount = this.#emptyResultFailures;
this.#emptyResultFailures = 0;View on GitHub (pinned to 9690622007)
Solutions
- Wrap the payload as {"result":{"data": <your output>}} for success.
- Report failure as {"result":{"error": "message"}}.
- Ensure `result` is a JSON object, not a scalar or array.
- If intentionally deferring to last-turn output, keep `type` set and omit both `data` and `error` per the useLastTurn path — otherwise include one of them.
Example fix
// before
yield({ result: "the answer", status: "success" })
// after
yield({ result: { data: "the answer" } }) Defensive patterns
Strategy: type-guard
Validate before calling
const r = params.result; if (typeof r !== "object" || r === null || Array.isArray(r) || !("data" in r) && !("error" in r)) throw new Error('result must be {data:...} or {error:...}'); Type guard
function hasResultRecord(p: unknown): p is { result: { data?: unknown; error?: string } } { const r = (p as { result?: unknown })?.result; return typeof r === "object" && r !== null && !Array.isArray(r) && ("data" in r || "error" in r); } Try / catch
try { await yield(params); } catch (e) { if (String(e.message).includes("result must be an object containing either data or error")) { return yield({ result: { data: params.result ?? params } }); } throw e; } Prevention
- Always nest payloads under result.data (or result.error for failures).
- Never pass scalars/arrays as `result`.
- Add result-shape validation to prompt/tool schema so models emit the right shape.
- Remember the last-turn fallback only applies when `type` is set and neither key is present.
When it happens
Trigger: Calling yield with `result` absent, `result` set to a non-object (string/number/array), or `result: {}` containing neither `data` nor `error` (and no usable `type`-based last-turn fallback).
Common situations: A model emits the payload at the top level instead of nesting under `result.data`; it puts data directly in `result` (`result: "text"`); it includes extra keys but forgets both `data` and `error`.
Related errors
- type must be a string or non-empty array of strings
- yield parameters schema is invalid
- Unsupported language '{value}'. Supported: {}
- Unable to infer language from file extension: {}. Specify `l
- Invalid pattern: {err}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/299c83472d92f36a.
Report an issue: GitHub.