can1357/oh-my-pi · error · ToolError

Protocol paths are not supported by ${op}(): ${rawPath}

Error message

Protocol paths are not supported by ${op}(): ${rawPath}

What it means

`resolveHelperPath` rewrites internal-URL paths (e.g. `local://x.md`) to on-disk roots supplied by the host via `ctx.localRoots()`. If the path uses an internal scheme that has no registered root (or is not an internal URL at all and does not resolve as a normal path), the helper refuses rather than guess a location. This keeps sandbox file I/O confined to host-approved directories.

Source

Thrown at packages/coding-agent/src/eval/js/shared/helpers.ts:116

function resolvePath(ctx: HelperContext, value: string): string {
	if (path.isAbsolute(value)) return path.normalize(value);
	return path.resolve(ctx.cwd(), value);
}

/**
 * Map a raw helper path to an absolute filesystem path. Plain paths resolve
 * against the cwd; an internal-URL whose scheme has an injected root (e.g.
 * `local://`) is rewritten under that root; any other `scheme://` is rejected
 * so we never silently create a literal `scheme:/` directory.
 */
function resolveHelperPath(ctx: HelperContext, rawPath: string, op: "read" | "write"): string {
	const match = INTERNAL_URL_RE.exec(rawPath);
	if (!match) return resolvePath(ctx, rawPath);
	const scheme = match[1].toLowerCase();
	const root = ctx.localRoots()[scheme];
	if (!root) {
		throw new ToolError(`Protocol paths are not supported by ${op}(): ${rawPath}`);
	}
	return resolveUnderRoot(scheme, root, match[2], rawPath);
}

/** Resolve an internal-URL relative path under its root, mirroring the host
 *  local-protocol handler: decode, reject absolute/traversal, confine to root. */
function resolveUnderRoot(scheme: string, root: string, rawRelative: string, rawPath: string): string {
	let relative: string;
	try {
		relative = decodeURIComponent(rawRelative.replaceAll("\\", "/"));
	} catch {
		throw new ToolError(`Invalid URL encoding in ${scheme}:// path: ${rawPath}`);
	}
	const rootPath = path.resolve(root);
	if (relative === "") return rootPath;
	if (path.isAbsolute(relative)) {
		throw new ToolError(`Absolute paths are not allowed in ${scheme}:// URLs: ${rawPath}`);
	}

View on GitHub (pinned to 9690622007)

Solutions

  1. Use a scheme that the session registers in localRoots (check the eval tool's localRoots option, e.g. `local`).
  2. Pass a plain relative or absolute filesystem path instead of a protocol URL if you do not need internal-root mapping.
  3. Register the scheme's root in the session config (localRoots) before running eval code that references it.

Example fix

// before
const txt = await read("artifact://report.md"); // scheme not registered
// after
const txt = await read("local://report.md"); // 'local' is a registered root
Defensive patterns

Strategy: validation

Validate before calling

const m = /^(\w+):\/\//.exec(p);
if (m && !(m[1] in registeredLocalRoots)) throw new Error(`unknown scheme: ${m[1]}`);

Try / catch

try {
	return await read(path);
} catch (err) {
	if (String(err?.message).startsWith("Protocol paths are not supported")) {
		return await read(path.replace(/^\w+:\/\//, "")); // retry as plain path
	}
	throw err;
}

Prevention

When it happens

Trigger: Calling `read()`/`write()` with a path like `scheme://file` where `scheme` is not present in the localRoots map for this session (e.g. using `artifact://` or `local://` when the session only registered `local`), or any URL-looking path that fails the INTERNAL_URL_RE and also fails normal resolution.

Common situations: Using an internal protocol the eval session never registered; typo in the scheme name; running eval code outside the host context that mounts local roots; version change renaming a scheme.

Related errors


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