{"record":{"id":"e1796d2188fddbc5","repo":"can1357/oh-my-pi","slug":"invalid-conflict-uri-raw-wildcard-conflict","errorCode":null,"errorMessage":"Invalid conflict URI '${raw}': wildcard 'conflict://*' does not accept a scope segment. Drop '/${scopePart}' or use a numeric id.","messagePattern":"Invalid conflict URI '(.+?)': wildcard 'conflict://\\*' does not accept a scope segment\\. Drop '/(.+?)' or use a numeric id\\.","errorType":"validation","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/conflict-detect.ts","lineNumber":292,"sourceCode":" * clear actionable message rather than a confusing \"not found\" later.\n *\n * `*` is the bulk-write wildcard — only valid as `conflict://*` (no\n * scope segment). Use it with `write({ path: \"conflict://*\", content })`\n * to apply `content` (with optional `@ours` / `@theirs` / `@base` /\n * `@both` shorthand) to every currently-registered conflict in one shot.\n */\nexport function parseConflictUri(raw: string): ParsedConflictUri | null {\n\tconst match = raw.match(CONFLICT_URI_RE);\n\tif (!match) return null;\n\tconst recoveredPrefix = match[1];\n\tconst tail = match[2];\n\tconst slashIdx = tail.indexOf(\"/\");\n\tconst idPart = slashIdx === -1 ? tail : tail.slice(0, slashIdx);\n\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) {","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/conflict-detect.ts#L274-L310","documentation":"parseConflictUri rejects a wildcard conflict URI that carries a scope segment. The wildcard conflict://* means 'apply to every currently-registered conflict' and is only valid bare; attaching /scope (e.g. conflict://*/ours) is meaningless because scopes are per-conflict, so the parser throws a ToolError with instructions to either drop the scope or use a specific numeric conflict id.","triggerScenarios":"Passing 'conflict://*/ours', 'conflict://*/theirs', or 'conflict://*/base' as the path argument to a read/write targeting conflicts; an agent templating a scoped URI and substituting * for the id.","commonSituations":"Agents or scripts that build URIs as `conflict://${id}/${scope}` with id='*' for bulk operations; copy-pasted examples mixing the wildcard bulk-write form with the per-id scope form.","solutions":["Drop the scope and use bare 'conflict://*' (contents can still use @ours/@theirs/@base/@both tokens for per-conflict resolution).","If you need a specific side, resolve a numeric id first (from a prior read that registered conflicts) and use 'conflict://<N>/<scope>'.","Fix URI construction so the wildcard never gets a scope segment appended."],"exampleFix":"// before\nwrite({ path: 'conflict://*/theirs', content });\n// after\nwrite({ path: 'conflict://*', content }); // @theirs tokens inside content resolve per-conflict","handlingStrategy":"validation","validationCode":"function isWildcardScoped(uri) {\n  return /^conflict:\\/\\/\\*\\//.test(uri) || /:conflict:\\/\\/\\*\\//.test(uri);\n}\nif (isWildcardScoped(path)) throw new Error('conflict://* takes no scope');","typeGuard":null,"tryCatchPattern":"try {\n  parseConflictUri(raw);\n} catch (err) {\n  if (String(err?.message).includes(\"does not accept a scope segment\")) {\n    raw = raw.replace(/\\/[^/]+$/, ''); // strip scope from wildcard\n  } else throw err;\n}","preventionTips":["Never append a scope to conflict://* — put @ours/@theirs/@base tokens in content instead.","Build URIs with a helper that special-cases the wildcard.","Resolve specific numeric ids when you need a particular side.","Validate URIs with a regex before passing them to read/write."],"tags":["conflict-resolution","uri-parsing","validation"],"backgroundTag":"invalid-uri-format","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}