can1357/oh-my-pi · error · ToolError

URL selector has multiple range groups; combine them with co

Error message

URL selector has multiple range groups; combine them with commas (e.g. `:5-10,20-30`).

What it means

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.

Source

Thrown at packages/coding-agent/src/tools/fetch.ts:189

export function parseReadUrlTarget(readPath: string): ParsedReadUrlTarget | null {
	const repaired = repairCollapsedScheme(readPath);
	const embedded = tryExtractEmbeddedUrlSelector(repaired);
	const urlPath = embedded?.path ?? repaired;
	if (!isReadableUrlPath(urlPath)) {
		return null;
	}

	let raw = false;
	let ranges: readonly LineRange[] | undefined;
	for (const sel of embedded?.sels ?? []) {
		if (sel.toLowerCase() === "raw") {
			raw = true;
			continue;
		}
		if (ranges !== undefined) {
			// Two range groups on the same URL (`…:5-10:20-30`) — combine with commas instead.
			throw new ToolError(
				`URL selector has multiple range groups; combine them with commas (e.g. \`:5-10,20-30\`).`,
			);
		}
		const parsed = parseLineRanges(sel);
		if (parsed === null) {
			// Shouldn't happen — isUrlSelectorToken vetted it. Belt-and-suspenders.
			throw new ToolError(`Invalid URL line selector: ${sel}`);
		}
		ranges = parsed;
	}

	if (!ranges || ranges.length === 0) return { path: urlPath, raw };
	if (ranges.length === 1) {
		const r = ranges[0];
		return {
			path: urlPath,
			raw,
			offset: r.startLine,

View on GitHub (pinned to 9690622007)

Solutions

  1. Merge the ranges into one comma-separated selector: `url:5-10,20-30`.
  2. Issue two separate read calls with one range each if comma syntax is not supported by your caller.
  3. If raw content plus a range is needed, keep the `raw` token and one comma-joined range group.

Example fix

// before
"https://example.com/data.txt:1-5:10-20"
// after
"https://example.com/data.txt:1-5,10-20"
Defensive patterns

Strategy: validation

Validate before calling

const m = url.match(/:([0-9,-]+(?:,[0-9,-]+)*)$/);
if (url.includes(":") && /:[0-9]+-[0-9]+:[0-9]/.test(url)) {
  url = url.replace(/:([0-9-]+):([0-9,-]+)/, ":$1,$2");
}

Type guard

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; }

Try / catch

try {
  await fetchTool.readUrl(id, { url: target }, signal);
} catch (e) {
  if (e instanceof ToolError && e.message.includes("multiple range groups")) {
    // normalize selector to comma form and retry once
  } else throw e;
}

Prevention

When it happens

Trigger: 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`.

Common situations: Users familiar with other tools' `start:end` colon syntax chaining ranges with extra colons; model-generated tool arguments guessing at multi-range syntax.

Related errors


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