can1357/oh-my-pi · error · ToolError

Cannot ${internalUrlAction} external URL: ${rawPath}. Use \`

Error message

Cannot ${internalUrlAction} external URL: ${rawPath}. Use \`read\` to fetch web content, then search the returned text.

What it means

When a rawPath matches a strict external URL scheme (http/https/ftp/ws/wss) but no external-URL resolver is configured or the resolvers decline it (e.g. ftp/ws/wss have none), resolveToolSearchScope throws this ToolError instead of letting the fallthrough produce a misleading 'Path not found'. Searching remote URLs directly is not supported for that scheme.

Source

Thrown at packages/coding-agent/src/tools/path-utils.ts:1538

			try {
				await fs.promises.stat(resolveToCwd(rawPath, cwd));
			} catch (err) {
				externalUrl = isEnoent(err) || isEnotdir(err);
			}
		}
		if (externalUrl) {
			const resolved = opts.resolveExternalUrl ? await opts.resolveExternalUrl(rawPath) : undefined;
			if (resolved) {
				resolvedPathInputs.push(resolved.sourcePath);
				if (opts.trackImmutableSources && resolved.immutable) {
					immutableSourcePaths.add(path.resolve(resolved.sourcePath));
				}
				continue;
			}
			// Resolver missing or declined (e.g. ftp/ws/wss): fail explicitly
			// instead of letting the local-path fallthrough surface a confusing
			// "Path not found" for a URL-shaped input.
			throw new ToolError(
				`Cannot ${internalUrlAction} external URL: ${rawPath}. Use \`read\` to fetch web content, then search the returned text.`,
			);
		}
		if (!internalRouter.canHandle(rawPath)) {
			resolvedPathInputs.push(rawPath);
			continue;
		}
		if (isSshUrl(rawPath)) {
			throw new ToolError(
				`Cannot ${internalUrlAction} a remote ssh:// path (no local file): ${rawPath}. Use \`read ${rawPath}\` to view it, or use \`grep\` on a specific remote file.`,
			);
		}
		if (hasGlobPathChars(rawPath)) {
			throw new ToolError(`Glob patterns are not supported for internal URLs: ${rawPath}`);
		}
		const resource = await internalRouter.resolve(rawPath, {
			cwd,
			settings: opts.settings,

View on GitHub (pinned to 9690622007)

Solutions

  1. Use the `read` tool on the URL to fetch its content, then run search/grep on the returned text or on the materialized local file.
  2. For https URLs with a resolver available, ensure the caller wires `resolveExternalUrl` into resolveToolSearchScope options.
  3. If the content exists locally, reference the local file path instead of the remote URL.

Example fix

// before
search({ pattern: "TODO", paths: ["https://example.com/page.html"] })
// after
const page = await read({ path: "https://example.com/page.html" });
searchInText(page.content, "TODO");
Defensive patterns

Strategy: fallback

Validate before calling

const EXTERNAL_URL_RE = /^(?:https?|ftp|ws|wss):\/\//i;
if (EXTERNAL_URL_RE.test(p)) {
  // route to read-then-search instead of search-scope resolution
}

Type guard

const isExternalUrl = (p) => /^(?:https?|ftp|ws|wss):\/\//i.test(p);

Try / catch

try { scope = await resolveToolSearchScope(opts); }
catch (e) {
  if (String(e.message).startsWith("Cannot ") && e.message.includes("external URL")) {
    const page = await read({ path: url });
    return searchInText(page.content, pattern);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling search/ast_grep with a scope entry like `https://example.com/data` or `ftp://host/file` while `resolveExternalUrl` is not provided (or returns undefined for that scheme) and internalUrlAction is e.g. `search`.

Common situations: Agent tries to grep a web page or API endpoint directly; user pastes a URL into the search tool's path parameter; ftp/ws URLs which the library deliberately does not materialize.

Related errors


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