can1357/oh-my-pi · error · ToolError
Invalid conflict URI '${raw}': must be 'conflict://<N>', 'co
Error message
Invalid conflict URI '${raw}': must be 'conflict://<N>', 'conflict://<N>/<scope>', or 'conflict://*' where N is a positive integer surfaced by a prior `read`. What it means
parseConflictUri throws this when the conflict id segment is not a positive integer (and not the '*' wildcard). Valid forms are conflict://<N>, conflict://<N>/<scope>, or conflict://*; anything else with the conflict:// scheme — 'conflict://abc', 'conflict://latest', 'conflict://3.2' — is rejected early with this message rather than failing later with a confusing not-found.
Source
Thrown at packages/coding-agent/src/tools/conflict-detect.ts:300
const match = raw.match(CONFLICT_URI_RE);
if (!match) return null;
const recoveredPrefix = match[1];
const tail = match[2];
const slashIdx = tail.indexOf("/");
const idPart = slashIdx === -1 ? tail : tail.slice(0, slashIdx);
const scopePart = slashIdx === -1 ? undefined : tail.slice(slashIdx + 1);
if (idPart === "*") {
if (scopePart !== undefined) {
throw new ToolError(
`Invalid conflict URI '${raw}': wildcard 'conflict://*' does not accept a scope segment. Drop '/${scopePart}' or use a numeric id.`,
);
}
return recoveredPrefix !== undefined ? { id: "*", recoveredPrefix } : { id: "*" };
}
if (!/^\d+$/.test(idPart)) {
throw new ToolError(
`Invalid conflict URI '${raw}': must be 'conflict://<N>', 'conflict://<N>/<scope>', or 'conflict://*' where N is a positive integer surfaced by a prior \`read\`.`,
);
}
const id = Number.parseInt(idPart, 10);
if (!Number.isFinite(id) || id < 1) {
throw new ToolError(`Invalid conflict URI '${raw}': id must be ≥ 1.`);
}
let scope: ConflictScope | undefined;
if (scopePart !== undefined) {
if (!CONFLICT_SCOPES.has(scopePart as ConflictScope)) {
throw new ToolError(
`Invalid conflict URI '${raw}': scope must be one of 'ours', 'theirs', 'base', or omitted (e.g. 'conflict://${id}/theirs').`,
);
}
scope = scopePart as ConflictScope;
}
View on GitHub (pinned to 9690622007)
Solutions
- Use the numeric id surfaced by a prior read of the file (conflict ids are assigned when conflicts are registered).
- Read the conflicted file first to register conflicts and obtain valid numeric ids, then reference them.
- Fix id interpolation in scripts/templates so a real number or '*' lands in the URI.
Example fix
// before
write({ path: 'conflict://latest', content });
// after
const id = conflicts[0].id; // from a prior read
write({ path: `conflict://${id}`, content }); Defensive patterns
Strategy: validation
Validate before calling
if (!/^(?:[^:]+:)?conflict:\/\/(\d+|\*)(?:\/(?:ours|theirs|base))?$/.test(path)) {
throw new Error(`not a valid conflict URI: ${path}`);
} Type guard
function isConflictUri(s) {
return /^(?:[^:]+:)?conflict:\/\/(\d+|\*)(?:\/(?:ours|theirs|base))?$/.test(s);
} Try / catch
try {
parseConflictUri(raw);
} catch (err) {
if (String(err?.message).includes("must be 'conflict://<N>'")) {
// recover: re-read the file to get numeric ids
} else throw err;
} Prevention
- Only use ids returned by a prior read's conflict registration.
- Never interpolate descriptive strings ('latest', 'first') into conflict URIs.
- Keep a registry mapping labels → numeric conflict ids.
- Validate URI shape before calling read/write.
When it happens
Trigger: Passing a non-numeric id like 'conflict://latest' or 'conflict://head'; including units or formatting ('conflict://3rd', 'conflict://#3'); an id placeholder left unsubstituted in a template.
Common situations: Agents hallucinating descriptive ids ('latest', 'first'); scripts interpolating undefined variables into the URI; ids copied from docs without replacing N.
Related errors
- Invalid conflict URI '${raw}': wildcard 'conflict://*' does
- Invalid conflict URI '${raw}': scope must be one of 'ours',
- Invalid conflict URI '${raw}': id must be ≥ 1.
- Conflict #${entry.id} has no base section (2-way merge). `@b
- Unsupported language '{value}'. Supported: {}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/7567318680f9f41c.
Report an issue: GitHub.