can1357/oh-my-pi · error · ToolError
path entry "${entry}" — only line-range selectors like ":50-
Error message
path entry "${entry}" — only line-range selectors like ":50-100" are supported (no ":raw"/":conflicts") What it means
In the non-internal-URL branch, parsePathSpecs parses the ':sel' suffix with parseLineRanges; grep only supports line-range selectors, so ':raw' or ':conflicts' (read-only selectors) fail to parse and are rejected with this error.
Source
Thrown at packages/coding-agent/src/tools/grep.ts:189
if (!isReadSelectorGrammar(internalSplit.sel)) {
throw new ToolError(
`path entry "${entry}" has an invalid selector ":${internalSplit.sel}" — use ":N-M" line ranges, ":raw"/":conflicts", a range plus ":raw", or percent-encode a literal ":" as %3A`,
);
}
specs.push({ original: entry, clean: internalSplit.path, ranges: selectorLineRanges(internalSplit.sel) });
continue;
}
// Prefer a literal filesystem match when one exists — a real file named
// `test:1-2` outranks the `:1-2` selector interpretation (issue #4618).
const strictSplit = splitPathAndSel(entry);
const split = await splitPathAndSelPreferringLiteral(entry, cwd);
const literalFilesystemMatch = strictSplit.sel !== undefined && split.sel === undefined;
let clean = literalFilesystemMatch ? resolveReadPath(entry, cwd) : entry;
let ranges: [LineRange, ...LineRange[]] | undefined;
if (!literalFilesystemMatch && split.sel) {
const parsed = parseLineRanges(split.sel);
if (!parsed) {
throw new ToolError(
`path entry "${entry}" — only line-range selectors like ":50-100" are supported (no ":raw"/":conflicts")`,
);
}
if (hasGlobPathChars(split.path)) {
throw new ToolError(`Line-range selector requires a single file, not a glob: ${entry}`);
}
clean = split.path;
ranges = parsed;
}
specs.push({
original: entry,
clean,
literalFilesystemMatch,
ranges,
});
}
return specs;
}View on GitHub (pinned to 9690622007)
Solutions
- Remove ':raw'/':conflicts' from the path entry and pass only a plain path or ':N-M' ranges
- Use the read tool if you need :raw/:conflicts selectors
- Search the whole file with grep and read specific chunks separately
Example fix
// before
await grepTool.execute({ pattern: "foo", path: "src/app.ts:raw" })
// after
await grepTool.execute({ pattern: "foo", path: "src/app.ts" }) Defensive patterns
Strategy: validation
Validate before calling
function stripReadOnlySelectors(entry: string): string {
return entry.replace(/:(raw|conflicts)$/i, "");
}
await grepTool.execute({ pattern, path: entries.map(stripReadOnlySelectors) }); Type guard
function hasReadOnlySelector(entry: string): boolean {
return /:(raw|conflicts)(:\d+-\d+)?$/.test(entry);
} Try / catch
try {
return await grepTool.execute({ pattern, path: entries });
} catch (err) {
if (err instanceof ToolError && err.message.includes(":raw\"/\":conflicts")) {
return await grepTool.execute({ pattern, path: entries.map(e => e.split(":")[0]) });
}
throw err;
} Prevention
- Do not share path-spec strings between the read tool and grep tool
- Strip :raw/:conflicts before calling grep
- Use the read tool for chunk-selector semantics
When it happens
Trigger: Path entries like 'file.ts:raw' or 'file.ts:conflicts' passed to grep; entry resolves as a literal filesystem match (strictSplit found a selector the normal split did not) and the selector is not a line range.
Common situations: Reusing read-tool arguments for grep; assuming grep supports raw/conflict chunk selectors like the read tool.
Related errors
- path entry "${entry}" has an invalid selector ":${internalSp
- Line-range selector requires a single file, not a glob: ${en
- Invalid regex: ${message.replace(/^Invalid regular expressio
- Replacement text is not valid UTF-8: {err}
- V2 compaction stream parse failed: ${err instanceof Error ?
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/20178e2614bae5d1.
Report an issue: GitHub.