{"record":{"id":"c9242a6af221bf18","repo":"can1357/oh-my-pi","slug":"invalid-conflict-uri-raw-id-must-be-1","errorCode":null,"errorMessage":"Invalid conflict URI '${raw}': id must be ≥ 1.","messagePattern":"Invalid conflict URI '(.+?)': id must be ≥ 1\\.","errorType":"validation","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/conflict-detect.ts","lineNumber":306,"sourceCode":"\tconst scopePart = slashIdx === -1 ? undefined : tail.slice(slashIdx + 1);\n\n\tif (idPart === \"*\") {\n\t\tif (scopePart !== undefined) {\n\t\t\tthrow new ToolError(\n\t\t\t\t`Invalid conflict URI '${raw}': wildcard 'conflict://*' does not accept a scope segment. Drop '/${scopePart}' or use a numeric id.`,\n\t\t\t);\n\t\t}\n\t\treturn recoveredPrefix !== undefined ? { id: \"*\", recoveredPrefix } : { id: \"*\" };\n\t}\n\n\tif (!/^\\d+$/.test(idPart)) {\n\t\tthrow new ToolError(\n\t\t\t`Invalid conflict URI '${raw}': must be 'conflict://<N>', 'conflict://<N>/<scope>', or 'conflict://*' where N is a positive integer surfaced by a prior \\`read\\`.`,\n\t\t);\n\t}\n\tconst id = Number.parseInt(idPart, 10);\n\tif (!Number.isFinite(id) || id < 1) {\n\t\tthrow new ToolError(`Invalid conflict URI '${raw}': id must be ≥ 1.`);\n\t}\n\n\tlet scope: ConflictScope | undefined;\n\tif (scopePart !== undefined) {\n\t\tif (!CONFLICT_SCOPES.has(scopePart as ConflictScope)) {\n\t\t\tthrow new ToolError(\n\t\t\t\t`Invalid conflict URI '${raw}': scope must be one of 'ours', 'theirs', 'base', or omitted (e.g. 'conflict://${id}/theirs').`,\n\t\t\t);\n\t\t}\n\t\tscope = scopePart as ConflictScope;\n\t}\n\n\treturn recoveredPrefix !== undefined ? { id, scope, recoveredPrefix } : { id, scope };\n}\n\n/** Result of {@link spliceConflict}: the new file text plus any boundary-echo repair applied. */\nexport interface ConflictSplice {\n\ttext: string;","sourceCodeStart":288,"sourceCodeEnd":324,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/conflict-detect.ts#L288-L324","documentation":"parseConflictUri throws this when the numeric id parses but is less than 1 (e.g. 'conflict://0'). Conflict ids are 1-based, assigned when a read registers conflicts, so 0 (or a parsed value that isn't finite) can never refer to a real conflict.","triggerScenarios":"Passing 'conflict://0' or a computed id that evaluated to 0; off-by-one logic treating conflict ids as zero-indexed; a variable defaulting to 0 when no conflict was found.","commonSituations":"Scripts using zero-based array indices directly as conflict ids; agents guessing id 0 for 'the first conflict' when the first id is 1.","solutions":["Use the actual 1-based id from the conflict entry (entry.id from the read result), not an array index.","Add 1 if you are mapping a zero-based list index to conflict ids — or better, read entry.id directly.","Guard your code: if no conflict was registered, don't construct a conflict:// URI at all."],"exampleFix":"// before\nconst uri = `conflict://${index}`; // index is 0-based\n// after\nconst uri = `conflict://${entry.id}`; // entry.id is 1-based","handlingStrategy":"validation","validationCode":"if (typeof id === 'number' && (!Number.isFinite(id) || id < 1)) {\n  throw new Error('conflict ids are 1-based; got ' + id);\n}\nconst uri = `conflict://${id}`;","typeGuard":"function isValidConflictId(id) {\n  return Number.isInteger(id) && id >= 1;\n}","tryCatchPattern":"try {\n  parseConflictUri(raw);\n} catch (err) {\n  if (String(err?.message).includes('id must be ≥ 1')) {\n    // id was 0 or invalid — re-derive from conflict entries\n  } else throw err;\n}","preventionTips":["Use entry.id (1-based), never zero-based array indices.","Check that a conflict actually exists before building its URI.","Default to 'no conflict' handling instead of id 0 when the list is empty."],"tags":["conflict-resolution","uri-parsing","off-by-one"],"backgroundTag":"invalid-uri-format","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}