{"record":{"id":"7761cca929671a37","repo":"can1357/oh-my-pi","slug":"glob-patterns-are-not-supported-for-internal-urls-7761cc","errorCode":null,"errorMessage":"Glob patterns are not supported for internal URLs: ${rawPath}","messagePattern":"Glob patterns are not supported for internal URLs: (.+?)","errorType":"validation","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/grep.ts","lineNumber":811,"sourceCode":"\t\tskipDirectoryListing: true,\n\t\t// Try path-only first so large artifacts (and any other handler that\n\t\t// separates path from content) resolve without materializing bytes.\n\t\t// Handlers that ignore the flag still return content, and virtual\n\t\t// resources without a sourcePath fall through to a second resolve.\n\t\tpathOnly: true,\n\t};\n\n\tfor (let idx = 0; idx < paths.length; idx++) {\n\t\tconst rawPath = paths[idx];\n\t\tif (!rawPath || opts.archiveDisplayMap.has(rawPath) || !internalRouter.canHandle(rawPath)) {\n\t\t\tcontinue;\n\t\t}\n\t\t// `ssh://[::1]/path` carries `[`/`]` in the IPv6 authority — glob metacharacters\n\t\t// — so check only the path portion for ssh:// (the SSH handler reads a single\n\t\t// remote file; there is no glob expansion). A glob in the remote path still trips.\n\t\tconst globTarget = /^ssh:\\/\\//i.test(rawPath) ? rawPath.replace(/^ssh:\\/\\/[^/]*/i, \"\") : rawPath;\n\t\tif (hasGlobPathChars(globTarget)) {\n\t\t\tthrow new ToolError(`Glob patterns are not supported for internal URLs: ${rawPath}`);\n\t\t}\n\t\tlet resource = await internalRouter.resolve(rawPath, context);\n\t\t// A directory listing with no backing local path (e.g. a remote ssh:// dir)\n\t\t// has no real contents to grep — searching its listing text would be\n\t\t// misleading. Local/skill/vault dir resources set `sourcePath` and skip this.\n\t\tif (resource.isDirectory && !resource.sourcePath) {\n\t\t\tthrow new ToolError(\n\t\t\t\t`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`,\n\t\t\t);\n\t\t}\n\t\tif (resource.sourcePath) {\n\t\t\tpaths[idx] = resource.sourcePath;\n\t\t\tif (resource.immutable) {\n\t\t\t\timmutableSourcePaths.add(path.resolve(resource.sourcePath));\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n","sourceCodeStart":793,"sourceCodeEnd":829,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/grep.ts#L793-L829","documentation":"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 `[`/`]`.","triggerScenarios":"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 `?`.","commonSituations":"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.","solutions":["Remove glob characters from the internal URL and grep the exact resource URL","If the resource has a backing local file (sourcePath), grep the local path instead and use `glob` there","For ssh:// hosts, grep a specific remote file path without wildcards, or list the directory with read first"],"exampleFix":"// before\nawait grep({ pattern: \"TODO\", path: \"ssh://host/logs/*.log\" });\n// after\nconst entries = await read(\"ssh://host/logs/\");\nawait grep({ pattern: \"TODO\", path: \"ssh://host/logs/app.log\" });","handlingStrategy":"validation","validationCode":"const target = /^ssh:\\/\\//i.test(p) ? p.replace(/^ssh:\\/\\/[^/]*/i, \"\") : p;\nif (/[*?\\[\\]]/.test(target)) throw new Error(`Remove glob chars from internal URL: ${p}`);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only use glob syntax on local filesystem paths, never on internal:// or ssh:// URLs","Remember IPv6 ssh authorities ([::1]) are exempt — check only the remote path portion"],"tags":["grep","glob","internal-url"],"backgroundTag":"glob-unsupported-for-url-scheme","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}