{"record":{"id":"4258edba0a92e75f","repo":"can1357/oh-my-pi","slug":"url-selector-has-multiple-range-groups-combine-th","errorCode":null,"errorMessage":"URL selector has multiple range groups; combine them with commas (e.g. `:5-10,20-30`).","messagePattern":"URL selector has multiple range groups; combine them with commas \\(e\\.g\\. `:5-10,20-30`\\)\\.","errorType":"exception","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/fetch.ts","lineNumber":189,"sourceCode":"\nexport function parseReadUrlTarget(readPath: string): ParsedReadUrlTarget | null {\n\tconst repaired = repairCollapsedScheme(readPath);\n\tconst embedded = tryExtractEmbeddedUrlSelector(repaired);\n\tconst urlPath = embedded?.path ?? repaired;\n\tif (!isReadableUrlPath(urlPath)) {\n\t\treturn null;\n\t}\n\n\tlet raw = false;\n\tlet ranges: readonly LineRange[] | undefined;\n\tfor (const sel of embedded?.sels ?? []) {\n\t\tif (sel.toLowerCase() === \"raw\") {\n\t\t\traw = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ranges !== undefined) {\n\t\t\t// Two range groups on the same URL (`…:5-10:20-30`) — combine with commas instead.\n\t\t\tthrow new ToolError(\n\t\t\t\t`URL selector has multiple range groups; combine them with commas (e.g. \\`:5-10,20-30\\`).`,\n\t\t\t);\n\t\t}\n\t\tconst parsed = parseLineRanges(sel);\n\t\tif (parsed === null) {\n\t\t\t// Shouldn't happen — isUrlSelectorToken vetted it. Belt-and-suspenders.\n\t\t\tthrow new ToolError(`Invalid URL line selector: ${sel}`);\n\t\t}\n\t\tranges = parsed;\n\t}\n\n\tif (!ranges || ranges.length === 0) return { path: urlPath, raw };\n\tif (ranges.length === 1) {\n\t\tconst r = ranges[0];\n\t\treturn {\n\t\t\tpath: urlPath,\n\t\t\traw,\n\t\t\toffset: r.startLine,","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/fetch.ts#L171-L207","documentation":"parseReadUrlTarget parses URL#selector suffixes for the fetch/read-URL tool. Line-range selectors are given as a single group like `:5-10` and multiple groups must be comma-joined (`:5-10,20-30`). If a second colon-separated range group appears (`url:5-10:20-30`) while one was already parsed, the parser throws this guidance error instead of silently misreading the target.","triggerScenarios":"Calling the fetch/read-URL tool with a URL target containing two colon-delimited range groups, e.g. `https://example.com/file.txt:1-5:10-20`.","commonSituations":"Users familiar with other tools' `start:end` colon syntax chaining ranges with extra colons; model-generated tool arguments guessing at multi-range syntax.","solutions":["Merge the ranges into one comma-separated selector: `url:5-10,20-30`.","Issue two separate read calls with one range each if comma syntax is not supported by your caller.","If raw content plus a range is needed, keep the `raw` token and one comma-joined range group."],"exampleFix":"// before\n\"https://example.com/data.txt:1-5:10-20\"\n// after\n\"https://example.com/data.txt:1-5,10-20\"","handlingStrategy":"validation","validationCode":"const m = url.match(/:([0-9,-]+(?:,[0-9,-]+)*)$/);\nif (url.includes(\":\") && /:[0-9]+-[0-9]+:[0-9]/.test(url)) {\n  url = url.replace(/:([0-9-]+):([0-9,-]+)/, \":$1,$2\");\n}","typeGuard":"function hasSingleRangeGroup(url: string): boolean { const parts = url.split(\":\"); const sel = parts.slice(2).join(\":\"); return !sel.split(\":\").every(p => /^raw$|^[0-9,-]+$/.test(p)) || sel.split(\":\").filter(p => /^[0-9,-]+$/.test(p)).length <= 1; }","tryCatchPattern":"try {\n  await fetchTool.readUrl(id, { url: target }, signal);\n} catch (e) {\n  if (e instanceof ToolError && e.message.includes(\"multiple range groups\")) {\n    // normalize selector to comma form and retry once\n  } else throw e;\n}","preventionTips":["Always comma-join multiple line ranges: `:5-10,20-30`.","Validate selector syntax before building tool arguments.","Restrict generated URLs to a single range group per call."],"tags":["url-parsing","syntax","fetch-tool","line-ranges"],"backgroundTag":"invalid-selector-syntax","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}