can1357/oh-my-pi · error · ToolError

Glob patterns are not supported for internal URLs: ${rawPath

Error message

Glob patterns are not supported for internal URLs: ${rawPath}

What it means

The grep tool refuses to run when an internal URL (internal://, ssh://, etc.) target contains glob metacharacters like `*`, `?`, or `[`/`]`. Internal router resources are resolved as single concrete URLs; there is no glob expansion against internal resources, so a glob-looking path would silently match nothing. For ssh:// URLs only the path portion (after the authority) is checked, because IPv6 literal authorities legitimately contain `[`/`]`.

Source

Thrown at packages/coding-agent/src/tools/grep.ts:811

		skipDirectoryListing: true,
		// Try path-only first so large artifacts (and any other handler that
		// separates path from content) resolve without materializing bytes.
		// Handlers that ignore the flag still return content, and virtual
		// resources without a sourcePath fall through to a second resolve.
		pathOnly: true,
	};

	for (let idx = 0; idx < paths.length; idx++) {
		const rawPath = paths[idx];
		if (!rawPath || opts.archiveDisplayMap.has(rawPath) || !internalRouter.canHandle(rawPath)) {
			continue;
		}
		// `ssh://[::1]/path` carries `[`/`]` in the IPv6 authority — glob metacharacters
		// — so check only the path portion for ssh:// (the SSH handler reads a single
		// remote file; there is no glob expansion). A glob in the remote path still trips.
		const globTarget = /^ssh:\/\//i.test(rawPath) ? rawPath.replace(/^ssh:\/\/[^/]*/i, "") : rawPath;
		if (hasGlobPathChars(globTarget)) {
			throw new ToolError(`Glob patterns are not supported for internal URLs: ${rawPath}`);
		}
		let resource = await internalRouter.resolve(rawPath, context);
		// A directory listing with no backing local path (e.g. a remote ssh:// dir)
		// has no real contents to grep — searching its listing text would be
		// misleading. Local/skill/vault dir resources set `sourcePath` and skip this.
		if (resource.isDirectory && !resource.sourcePath) {
			throw new ToolError(
				`grep cannot recurse the directory listing at ${rawPath}; grep a specific file under it (e.g. ${rawPath.replace(/\/+$/, "")}/<file>) or read ${rawPath} to list its entries`,
			);
		}
		if (resource.sourcePath) {
			paths[idx] = resource.sourcePath;
			if (resource.immutable) {
				immutableSourcePaths.add(path.resolve(resource.sourcePath));
			}
			continue;
		}

View on GitHub (pinned to 9690622007)

Solutions

  1. Remove glob characters from the internal URL and grep the exact resource URL
  2. If the resource has a backing local file (sourcePath), grep the local path instead and use `glob` there
  3. For ssh:// hosts, grep a specific remote file path without wildcards, or list the directory with read first

Example fix

// before
await grep({ pattern: "TODO", path: "ssh://host/logs/*.log" });
// after
const entries = await read("ssh://host/logs/");
await grep({ pattern: "TODO", path: "ssh://host/logs/app.log" });
Defensive patterns

Strategy: validation

Validate before calling

const target = /^ssh:\/\//i.test(p) ? p.replace(/^ssh:\/\/[^/]*/i, "") : p;
if (/[*?\[\]]/.test(target)) throw new Error(`Remove glob chars from internal URL: ${p}`);

Prevention

When it happens

Trigger: Calling grep with a `path` that is an internal URL containing glob characters, e.g. `internal://bundle/src/**/*.ts` or `ssh://host/data/*.log`. Also triggered by an ssh:// remote path containing `*` or `?`.

Common situations: Copying a local glob grep invocation and prefixing it with an internal:// or ssh:// scheme; embedding an IPv6 address in ssh:// is fine (authority stripped before the check), but a wildcard in the remote path trips it.

Related errors


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