can1357/oh-my-pi · error

Unknown protocol: ${scheme}:// Supported: ${available || "no

Error message

Unknown protocol: ${scheme}://
Supported: ${available || "none"}

What it means

The internal URL router dispatches by scheme to registered protocol handlers. #route throws this when the scheme of the URL has no registered handler (and is not an accepted mcp-resource scheme), listing all currently supported schemes in the message.

Source

Thrown at packages/coding-agent/src/internal-urls/router.ts:132

		if (!handler?.complete) return null;
		return handler.complete(query, context);
	}

	#isMcpResourceScheme(scheme: string): boolean {
		return !["file", "http", "https"].includes(scheme) && this.#handlers.has("mcp");
	}

	#route(input: string, allowMcpResource = false): { parsed: InternalUrl; handler: ProtocolHandler } {
		const parsed = parseInternalUrl(input);
		const scheme = parsed.protocol.replace(/:$/, "").toLowerCase();
		const handler =
			this.#handlers.get(scheme) ??
			(allowMcpResource && this.#isMcpResourceScheme(scheme) ? this.#handlers.get("mcp") : undefined);
		if (!handler) {
			const available = Array.from(this.#handlers.keys())
				.map(candidate => `${candidate}://`)
				.join(", ");
			throw new Error(`Unknown protocol: ${scheme}://\nSupported: ${available || "none"}`);
		}
		return { parsed, handler };
	}

	/** Resolve an internal URL through its registered protocol handler. */
	async resolve(input: string, context?: ResolveContext): Promise<InternalResource> {
		const { parsed, handler } = this.#route(input, true);
		const resource = await handler.resolve(parsed, context);
		return { ...resource, immutable: resource.immutable ?? handler.immutable };
	}

	/** Write an internal URL through its registered protocol handler. */
	async write(input: string, content: string, context?: WriteContext): Promise<void> {
		const { parsed, handler } = this.#route(input);
		if (!handler.write) {
			const scheme = parsed.protocol.replace(/:$/, "").toLowerCase();
			throw new Error(`${scheme}:// URLs are read-only for write; use the protocol-specific tool for mutations.`);
		}

View on GitHub (pinned to 9690622007)

Solutions

  1. Use a supported scheme from the error's 'Supported:' list (e.g. omp://, memory://, rule://).
  2. Fix typos in the scheme name.
  3. If you intended an mcp:// resource URL, route it where MCP resources are allowed (allowMcpResource enabled).
  4. Handle file/web URLs with the normal file-read or HTTP tooling, not the internal router.

Example fix

// before
await router.resolve('https://example.com');
// after: check scheme first
const scheme = new URL(input).protocol.replace(/:$/, '').toLowerCase();
if (!['omp', 'memory', 'rule'].includes(scheme)) throw new Error(`use a native tool for ${scheme}://`);
await router.resolve(input);
Defensive patterns

Strategy: validation

Validate before calling

const supported = ['omp', 'memory', 'rule']; // keep in sync with registered handlers
const scheme = input.split('://')[0]?.toLowerCase();
if (!scheme || !supported.includes(scheme)) throw new Error(`unsupported internal scheme: ${scheme ?? input}`);

Type guard

const isInternalUrl = (s: string): boolean =>
  ['omp', 'memory', 'rule'].includes(s.split('://')[0]?.toLowerCase() ?? '');

Try / catch

try {
  return await router.resolve(input);
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Unknown protocol:')) {
    logger.warn('unhandled internal URL scheme', { input });
    return null;
  }
  throw err;
}

Prevention

When it happens

Trigger: Resolving or writing a URL like file://..., https://..., or a typo'd scheme (e.g. 'omps://') through the internal-URL router, which only handles registered internal schemes.

Common situations: Confusing internal URLs with regular web/file URLs; typos in the scheme; calling the router with an MCP scheme while MCP resource support is disabled (allowMcpResource false).

Related errors


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