can1357/oh-my-pi · error · ToolError

Conflict #${entry.id} no longer present in '${entry.displayP

Error message

Conflict #${entry.id} no longer present in '${entry.displayPath}': the recorded marker block can't be located. The file changed since the conflict was registered — re-read it to re-register conflicts.

What it means

spliceConflict locates the conflict marker block recorded when the conflict was registered (anchored to the recorded start line, matched by content). If the marker block — the <<<<<<< / ======= / >>>>>>> lines and the recorded side content — can no longer be found in the file's current text, resolution cannot proceed safely, so it throws. Line-number shifts from earlier edits are tolerated; actual content changes to the block are not.

Source

Thrown at packages/coding-agent/src/tools/conflict-detect.ts:354

 * block by content (anchored to `entry.startLine` as the preferred
 * match), so out-of-band edits earlier in the file that shift line
 * numbers don't break resolution. Throws clearly when the marker block
 * has actually been altered or removed.
 *
 * Boundary-echo repair (same philosophy as the edit tool's hashline
 * keeper repair): models frequently paste the "whole resolved function"
 * including the lines that live directly before/after the marker block,
 * which the verbatim splice would duplicate. Replacement lines that
 * exactly echo the adjacent context are dropped when the echo is
 * unambiguous — two or more consecutive lines, or a single line whose
 * removal fixes a delimiter-balance mismatch against the recorded sides.
 */
export function spliceConflict(originalText: string, entry: ConflictEntry, replacement: string): ConflictSplice {
	const lines = originalText.split("\n");
	const expected = buildRecordedRegion(entry);
	const match = locateRegion(lines, expected, entry.startLine - 1);
	if (!match) {
		throw new ToolError(
			`Conflict #${entry.id} no longer present in '${entry.displayPath}': the recorded marker block can't be located. The file changed since the conflict was registered — re-read it to re-register conflicts.`,
		);
	}

	const trimmed = normalizeTrailingNewline(replacement);
	let replacementLines = trimmed.split("\n").map(stripTrailingCr);
	const echo = trimBoundaryEcho(replacementLines, lines, match, entry);
	replacementLines = echo.lines;
	// Round-trip fidelity for CRLF files: recorded sections are LF-normalized,
	// so re-apply \r to spliced lines when the matched region used CRLF. The
	// final replacement line only carries \r when another line follows it.
	if (lines[match.startIdx]!.endsWith("\r")) {
		const hasFollowingLine = match.endIdx + 1 < lines.length;
		replacementLines = replacementLines.map((l, i) =>
			i < replacementLines.length - 1 || hasFollowingLine ? `${l}\r` : l,
		);
	}
	const next = [...lines.slice(0, match.startIdx), ...replacementLines, ...lines.slice(match.endIdx + 1)];

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-read the file so conflicts are re-registered against the current content, then resolve using the new ids.
  2. Check the file's current state (git diff / open it) to see what changed since registration before retrying.
  3. If a formatter is interfering, disable it for that file or format before reading, then resolve.
  4. Re-run resolution in one step: read → write conflict://<new-id> without intermediate edits.

Example fix

// before
// conflict #3 registered earlier; file edited since
write({ path: 'conflict://3', content: '@theirs' }); // throws
// after
const reread = await read({ path: file }); // re-registers conflicts
const newId = reread.conflicts[0].id;
write({ path: `conflict://${newId}`, content: '@theirs' });
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await write({ path: `conflict://${entry.id}`, content });
} catch (err) {
  if (String(err?.message).includes('no longer present')) {
    const reread = await read({ path: entry.displayPath }); // re-register conflicts
    const fresh = reread.conflicts.find(c => c.id);
    await write({ path: `conflict://${fresh.id}`, content });
  } else throw err;
}

Prevention

When it happens

Trigger: The file was edited (manually, by another tool, by a linter/formatter) after the conflict was registered and before the conflict:// write; the conflict markers were partially resolved or deleted; a formatter reflowed the conflict block's contents.

Common situations: Formatters (prettier, gofmt) rewriting the file between read and resolve; the agent editing the file with the normal edit tool in between; a user fixing conflicts by hand in an editor while an agent works on them; stale conflict registrations across sessions or rebases.

Related errors


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