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.
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
- data is required when yield indicates success
- result must contain either \`data\` or \`error\`. Use \
- does not match schema: .
- Section uses unknown incremental yield label(s): . Resubmit…
- This task requires structured output matching the declared…
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/f46a622e47922ce6.
Report an issue: GitHub.
Appendix: 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)