can1357/oh-my-pi · error · ToolError

Invalid URL line selector: ${sel}

Error message

Invalid URL line selector: ${sel}

What it means

Belt-and-suspenders branch in parseReadUrlTarget: after isUrlSelectorToken has already vetted selector tokens, parseLineRanges is expected to always succeed. If it returns null, the token was vetted as a selector but is not a parseable line range, so this error fires. Hitting it in practice means a selector token slipped past the vetting or the range grammar changed.

Source

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

	}

	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,
			limit: r.endLine !== undefined ? r.endLine - r.startLine + 1 : undefined,
		};
	}
	return { path: urlPath, raw, ranges };
}

/**

View on GitHub (pinned to 9690622007)

Solutions

  1. Use a plain, well-formed range selector such as `:5` or `:5-10` (comma-join multiple ranges).
  2. Drop the selector entirely to read the whole URL.
  3. If you believe the selector is valid, it is a vet/parser mismatch bug — report it with the exact URL used.

Example fix

// before
"https://example.com/file.txt:abc"
// after
"https://example.com/file.txt:1-10"
Defensive patterns

Strategy: validation

Validate before calling

function validSelector(sel: string): boolean { return /^raw$|^[0-9]+(-[0-9]+)?(,[0-9]+(-[0-9]+)?)*$/.test(sel); }
if (!validSelector(sel)) throw new Error(`bad selector: ${sel}`);

Type guard

function isLineRangeSelector(sel: string): boolean { return /^[0-9]+(-[0-9]+)?(,[0-9]+(-[0-9]+)?)*$/.test(sel); }

Try / catch

try {
  await fetchTool.readUrl(id, { url }, signal);
} catch (e) {
  if (e instanceof ToolError && e.message.startsWith("Invalid URL line selector")) {
    // drop the selector or fix it, then retry
  } else throw e;
}

Prevention

When it happens

Trigger: Passing a URL selector token that passes isUrlSelectorToken but fails parseLineRanges — e.g. a malformed or hypothetical future selector form like `:abc` if vetting rules drift out of sync with the range parser.

Common situations: Rare in practice due to pre-vetting; most likely after a version upgrade where the selector grammar changed, or from hand-crafted URLs with exotic selector tokens.

Related errors


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