can1357/oh-my-pi · error · Error

git apply --3way failed for task

Error message

git apply --3way failed for task ${taskId}: ${stderr}

What it means

When merging an isolated task's patch back into the parent worktree, the code first tries plain `git apply`, then retries with `git apply --3way`. If the three-way attempt also fails, it logs diagnostics (exit code, stderr, patch head) and throws with the git stderr embedded so the conflict cause is visible.

Solutions

  1. Read the embedded stderr to find the conflicting file(s); manually apply the task's changes or rebase them
  2. Reduce conflict window: merge task results promptly, or re-run the task against the current parent HEAD
  3. If binary files conflict, apply those hunks manually
Defensive patterns

Strategy: try-catch

Validate before calling

// dry-run the patch before the real 3-way apply
const probe = await $`git apply --check --3way patch.diff`.cwd(repoDir).quiet().nothrow();
if (probe.exitCode !== 0) console.error(probe.stderr.text());

Try / catch

try {
	await mergeTaskPatch(taskId, patchText);
} catch (err) {
	if ((err as Error).message.startsWith("git apply --3way failed")) {
		// rebase task branch onto current HEAD and regenerate patch
	}
	throw err;
}

Prevention

When it happens

Trigger: Calling the patch-application path for a task whose diff cannot be applied even with 3-way merge: files changed in both the task worktree and the parent (real conflicts), missing context, or paths deleted/renamed in the parent since the task started.

Common situations: Long-running subagent tasks whose target files were edited in the main worktree meanwhile; binary files (git apply --3way can't merge binaries); patches produced against a stale baseline commit.

Related errors


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

Appendix: source

Thrown at packages/coding-agent/src/task/worktree.ts:660

		try {
			await repo.applyPatch(patchText, { threeWay: true });
		} catch (err) {
			if (!vcs.isVcsError(err)) throw err;
			threeWayErr = err;
		}
		if (threeWayErr) {
			const wipPatches = collectWipPatches(baselineWip);
			if (wipPatches.length === 0 || !baselineWip) {
				const stderr = threeWayErr.stderr.slice(0, 2000);
				logger.error("commitToBranch: git apply --3way failed", {
					taskId,
					exitCode: threeWayErr.exitCode,
					stderr,
					initialStderr: plainErr.stderr.slice(0, 2000),
					patchSize: patchText.length,
					patchHead: patchText.slice(0, 500),
				});
				throw new Error(`git apply --3way failed for task ${taskId}: ${stderr}`);
			}
			try {
				// `git apply --3way` leaves conflict markers in `U` files when
				// it can't resolve; reset the worktree so the WIP-seeded retry
				// starts from a clean HEAD tree.
				await repo.reset("hard", "HEAD");
				await applyDeltaOverBaselineWip(tmpDir, taskId, patchText, wipPatches, baselineWip);
			} catch (wipErr) {
				if (!vcs.isVcsError(wipErr)) throw wipErr;
				const stderr = wipErr.stderr.slice(0, 2000);
				logger.error("commitToBranch: git apply with baseline WIP failed", {
					taskId,
					exitCode: wipErr.exitCode,
					stderr,
					threeWayStderr: threeWayErr.stderr.slice(0, 2000),
					initialStderr: plainErr.stderr.slice(0, 2000),
					patchSize: patchText.length,
					patchHead: patchText.slice(0, 500),

View on GitHub (pinned to 9690622007)