can1357/oh-my-pi · error
result cannot contain both data and error
Error message
result cannot contain both data and error
What it means
The yield tool for subagent results rejects a submission that supplies both `data` (success payload) and `error` (failure message) at once. A result is either a success or a failure — including both is ambiguous, so execute() throws early instead of guessing. The tool schema should already prevent this, but direct calls or malformed tool args can slip past validation.
Source
Thrown at packages/coding-agent/src/tools/yield.ts:382
_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;
const error =
`yield result stayed empty after ${attemptCount} consecutive attempt(s); aborting child instead of retrying forever. ` +
'Submit success as `{ "result": { "data": <your output> } }` or failure as `{ "result": { "error": "message" } }`.';
return {
content: [{ type: "text", text: `Task aborted: ${error}` }],
details: {
data: undefined,
status: "aborted",
error,
type: yieldType,
},
};View on GitHub (pinned to 9690622007)
Solutions
- Remove the `error` field and submit {result: {data: ...}} for a successful outcome
- Remove `data` and submit {result: {error: "message"}} if the task failed
- Ensure failed/absent values are `undefined`, not empty strings or placeholder text, so the mutually-exclusive check passes
- Fix the tool-call argument construction in the calling harness so it never emits both keys
Example fix
// before
yield({ result: { data: { findings }, error: "none" } });
// after
yield({ result: { data: { findings } } }); Defensive patterns
Strategy: validation
Validate before calling
function canYield(r) { return (r.data === undefined) !== (r.error === undefined); }
if (!canYield(result)) throw new TypeError('yield result must have exactly one of data or error'); Type guard
function isExclusiveResult(r) {
const hasData = r.data !== undefined;
const hasError = r.error !== undefined;
return hasData !== hasError;
} Try / catch
try {
yield({ result });
} catch (err) {
if (err.message.includes('both data and error')) {
yield({ result: result.error !== undefined ? { error: result.error } : { data: result.data } });
} else throw err;
} Prevention
- Always build yield results through a single helper that picks data OR error
- Never set error to placeholder strings like "none" or "" — use undefined
- Validate tool args against the yield schema before submission
When it happens
Trigger: Calling the yield tool (via result/section/finalize/overrideResult) with both `data` and `error` defined in the result payload, e.g. {result: {data: {...}, error: "something"}}.
Common situations: A model or agent harness copies a result template and forgets to delete the `error` field; a wrapper always sets `error: undefined` but a bug turns it into a string like "none" or "" (non-undefined); hand-crafted RPC/tool-call payloads bypass schema validation.
Related errors
- result must contain either \`data\` or \`error\`. Use \`{res
- data is required when yield indicates success
- Section ${formatYieldLabels(yieldType as string[])} uses unk
- This task requires structured output matching the declared s
- ${scope} does not match schema: ${formatAllValidationIssues(
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/f46a622e47922ce6.
Report an issue: GitHub.