can1357/oh-my-pi · error

Invalid URL encoding in local:// path: ${url.href}

Error message

Invalid URL encoding in local:// path: ${url.href}

What it means

extractRelativePath percent-decodes the host+pathname of a local:// URL so the resulting path segments match on-disk names. If decodeURIComponent throws (the string contains a stray '%' not followed by two hex digits, or malformed UTF-8 sequences), the handler rethrows with this message including the URL href.

Source

Thrown at packages/coding-agent/src/internal-urls/local-protocol.ts:232

	const pathname = url.rawPathname ?? url.pathname;

	const combined = host
		? pathname && pathname !== "/"
			? `${host}${pathname}`
			: host
		: pathname && pathname !== "/"
			? pathname.slice(1)
			: "";

	if (!combined) {
		return "";
	}

	let decoded: string;
	try {
		decoded = decodeURIComponent(combined.replaceAll("\\", "/"));
	} catch {
		throw new Error(`Invalid URL encoding in local:// path: ${url.href}`);
	}
	try {
		validateRelativePath(decoded);
	} catch (error) {
		throw toLocalValidationError(error);
	}
	return decoded;
}

/** Resolve the session-scoped local:// root, shortening long Windows artifact paths before writes hit MAX_PATH. */
export function resolveLocalRoot(options: LocalProtocolOptions, platform: NodeJS.Platform = process.platform): string {
	const artifactsDir = options.getArtifactsDir?.();
	if (artifactsDir) {
		const candidate = path.resolve(artifactsDir, "local");
		if (platform === "win32" && candidate.length >= WINDOWS_LOCAL_ROOT_MAX_CHARS) {
			return shortLocalRoot(options);
		}
		return candidate;

View on GitHub (pinned to 9690622007)

Solutions

  1. Percent-encode path segments when building the URL: `local://` + encodeURIComponent(segment) for each segment.
  2. Encode a literal '%' as '%25' in the URL.
  3. If the URL came from upstream code, fix the producer to use proper encoding rather than string concatenation.

Example fix

// before
const url = `local://${name}`; // name = '50%_off.md'
// after
const url = `local://${encodeURIComponent(name)}`; // 50%25_off.md
Defensive patterns

Strategy: validation

Validate before calling

function buildLocalUrl(name) { return 'local://' + encodeURIComponent(name); }
// validate an existing URL:
try { decodeURIComponent(url.replace(/^local:\/\//, '')); } catch { throw new Error(`Malformed percent-encoding in ${url}`); }

Try / catch

try { resource = await handler.resolve(url, ctx); } catch (e) { if (String(e.message).startsWith('Invalid URL encoding')) { /* re-encode segments and retry once */ } else throw e; }

Prevention

When it happens

Trigger: Resolving local://foo%zz.txt or local://100% where the percent escape is invalid; concatenating a pre-encoded path with a raw '%' character; URLs built by naive string templating instead of encodeURIComponent.

Common situations: Filenames containing literal '%' (e.g. '50%_off.md') written into the URL unescaped; double-encoding bugs where a component was encoded twice; model-generated local:// URLs with malformed escapes.

Related errors


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