can1357/oh-my-pi · error · ToolError
Cannot search archive member(s): ${archiveUnreadable.join(",
Error message
Cannot search archive member(s): ${archiveUnreadable.join(", ")}. Read the member with `read <archive>:<member>` and inspect the returned text, or pass a UTF-8 text member. What it means
Every path passed to grep was an archive member selector (e.g. archive.tar.gz:inner.txt) that could not be materialized as searchable text — typically because the member is binary or not decodable as UTF-8 — and there were no other searchable or virtual paths to fall back on. The tool surfaces this reason instead of letting the scope resolver emit a confusing "path not found".
Source
Thrown at packages/coding-agent/src/tools/grep.ts:1014
cwd: this.session.cwd,
settings: this.session.settings,
signal,
archiveDisplayMap,
localProtocolOptions: this.session.localProtocolOptions,
skills: this.session.skills,
sessionFile: this.session.getSessionFile() ?? undefined,
});
const searchablePaths = internalResolution.paths;
const { virtualResources, virtualPathSet, virtualInputIndexes } = internalResolution;
const rangesByAbsPath = new Map<string, LineRange[]>();
if (
archiveUnreadable.length > 0 &&
searchablePaths.length === archiveUnreadable.length &&
virtualResources.length === 0
) {
// All inputs were archive selectors we couldn't materialize; surface the
// reason instead of a downstream "path not found" from the scope resolver.
throw new ToolError(
`Cannot search archive member(s): ${archiveUnreadable.join(", ")}. ` +
`Read the member with \`read <archive>:<member>\` and inspect the returned text, ` +
`or pass a UTF-8 text member.`,
);
}
const normalizedContextBefore = this.#contextOverride ?? this.session.settings.get("grep.contextBefore");
const normalizedContextAfter = this.#contextOverride ?? this.session.settings.get("grep.contextAfter");
const ignoreCase = !(caseSensitive ?? true);
const useGitignore = gitignore ?? true;
const patternHasNewline = normalizedPattern.includes("\n") || normalizedPattern.includes("\\n");
const effectiveMultiline = patternHasNewline;
let searchPath: string;
let scopePath: string;
let globFilter: string | undefined;
let isDirectory: boolean;
let multiTargets: ResolvedSearchTarget[] | undefined;View on GitHub (pinned to 9690622007)
Solutions
- Extract the member's text via `read <archive>:<member>` and inspect the returned text
- Pass a UTF-8 text member of the archive instead of the binary one
- Include at least one normal (non-archive) path in the semicolon-delimited `path` list so the search can proceed on the other targets
Example fix
// before
await grep({ pattern: "version", path: "app.tar.gz:assets/logo.png" });
// after
const pkg = await read("app.tar.gz:package.json");
await grep({ pattern: "version", path: "app.tar.gz:package.json" }); Defensive patterns
Strategy: fallback
Try / catch
try {
await grep({ pattern, path: "data.tar.gz:blob.bin" });
} catch (err) {
if (err instanceof ToolError && err.message.startsWith("Cannot search archive member")) {
const text = await read("data.tar.gz:README.md"); // fall back to a text member
} else throw err;
} Prevention
- Only select UTF-8 text members for grep; read binary members instead
- Verify member names/types by reading the archive listing first
When it happens
Trigger: grep with path set exclusively to archive member selectors whose contents cannot be extracted as UTF-8 text, e.g. `grep tgz:data.tar.gz:bin/image.png` or a compressed binary member.
Common situations: Grepping inside a tar/zip for a binary asset by mistake; typos in the member name selecting a binary file; expecting the tool to search binary contents.
Related errors
- archive destination exists: ${destSession}
- archive destination exists: ${legacyDestSession}
- archive artifacts destination exists: ${destArtifacts}
- Legacy GrepToolOptions.operations is not supported: the buil
- Glob patterns are not supported for internal URLs: ${rawPath
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/a376ec2116e3451c.
Report an issue: GitHub.