can1357/oh-my-pi · error · ToolError

Conflict #${id} not found. Conflict ids are registered when

Error message

Conflict #${id} not found. Conflict ids are registered when `read` surfaces a marker block; re-read the file to get a current id.

What it means

Conflict ids are registered only when the `read` tool surfaces a conflict marker block, stored in the session's conflict history. Looking up an id that was never registered (or has been cleared) throws this ToolError telling the caller to re-read the file to obtain a current id.

Source

Thrown at packages/coding-agent/src/tools/write.ts:918

		return {
			content: [{ type: "text", text: resultText }],
			details: { resolvedPath: absolutePath },
		};
	}

	/**
	 * Look up a single conflict entry by id and dispatch to {@link #resolveConflict}.
	 * Throws a clear `not found` error when the id has been invalidated.
	 */
	async #resolveSingleConflictById(
		id: number,
		replacementContent: string,
		stripped: boolean,
		signal: AbortSignal | undefined,
	): Promise<AgentToolResult<WriteToolDetails>> {
		const entry = getConflictHistory(this.session).get(id);
		if (!entry) {
			throw new ToolError(
				`Conflict #${id} not found. Conflict ids are registered when \`read\` surfaces a marker block; re-read the file to get a current id.`,
			);
		}
		return this.#resolveConflict(entry, replacementContent, stripped, signal);
	}

	/**
	 * Bulk-resolve every registered conflict via `conflict://*`.
	 *
	 * Entries are grouped by file and applied bottom-up by recorded start
	 * line so each splice keeps later anchors valid. `content` tokens are
	 * expanded *per entry*, so `content: "@ours"` keeps each block's own
	 * ours side rather than collapsing every conflict to the first
	 * block's ours.
	 *
	 * All-or-nothing semantics within a file: if any splice for a file
	 * fails (stale anchors, missing base for `@base`, etc.), that file is
	 * left untouched and the error is surfaced. Files that succeed are

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-read the file containing the conflict markers to get fresh, currently valid ids.
  2. List currently registered conflicts (the conflict://* flow reports registered ids in related errors).
  3. Use conflict://* with per-id directives once you know the valid ids.
  4. Don't persist conflict ids across sessions — they are session-scoped.
Defensive patterns

Strategy: type-guard

Validate before calling

// keep a local set of ids obtained from the most recent conflict-surfacing read
const knownIds = new Set([1, 2, 5]);
if (!knownIds.has(id)) throw new Error(`#${id} is not a registered conflict id`);

Type guard

function isRegisteredConflictId(id: number, entries: { id: number }[]): boolean {
  return entries.some(e => e.id === id);
}

Try / catch

try {
  await write(`conflict://${id}`, replacement);
} catch (err) {
  if (String(err.message).includes("not found")) {
    // re-read the file to refresh conflict ids, then retry
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling write with conflict://<id> where the id is wrong, was from a previous session, references a conflict that was already resolved and evicted, or the file was never re-read after new conflicts appeared.

Common situations: Agent hallucinating an id, reusing ids after session restart, stale ids cached in agent notes after another resolution pass consumed them, ids referencing files not read with the conflict-surfacing read path.

Related errors


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