can1357/oh-my-pi · error · Error

OAuth redirect URI must not include surrounding whitespace

Error message

OAuth redirect URI must not include surrounding whitespace

What it means

resolveRedirectUri validates the configured OAuth redirect URI before it is used in the authorization flow. It trims the value to decide whether it is present, and if the trimmed value differs from the configured one, the config contains leading/trailing whitespace — which would make the redirect URI mismatch the one registered at the authorization server. The library rejects it up front instead of failing later at the provider with redirect_uri mismatch.

Source

Thrown at packages/coding-agent/src/mcp/oauth-flow.ts:138

 */
async function readRegistrationFailureDetail(response: Response): Promise<string | undefined> {
	try {
		return truncateDetail(await response.text());
	} catch {
		return undefined;
	}
}

function isLoopbackHostname(hostname: string): boolean {
	return hostname === "localhost" || hostname === "127.0.0.1";
}

function resolveRedirectUri(redirectUri: string | undefined): string | undefined {
	const configured = redirectUri;
	const trimmed = configured?.trim();
	if (!trimmed) return undefined;
	if (trimmed !== configured) {
		throw new Error("OAuth redirect URI must not include surrounding whitespace");
	}

	const parsed = new URL(configured);
	if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
		throw new Error("OAuth redirect URI must use http or https");
	}
	return configured;
}

function parseRedirectUri(redirectUri: string | undefined): URL | undefined {
	return redirectUri ? new URL(redirectUri) : undefined;
}

function getUriPort(uri: URL): number {
	if (uri.port !== "") return Number(uri.port);
	return uri.protocol === "https:" ? 443 : 80;
}

View on GitHub (pinned to 9690622007)

Solutions

  1. Remove the surrounding whitespace from the configured redirect URI
  2. If the value comes from an env var, trim it at the source or fix how it is exported (e.g. quoted heredoc artifacts)
  3. Validate config at load time: compare value to value.trim() and reject or trim before passing to the OAuth flow

Example fix

// before
"redirectUri": "  http://localhost:1455/auth/callback "
// after
"redirectUri": "http://localhost:1455/auth/callback"
Defensive patterns

Strategy: validation

Validate before calling

const uri = config.oauth?.redirectUri;
if (uri != null && uri.trim() !== uri) {
  throw new Error(`redirectUri has surrounding whitespace: ${JSON.stringify(uri)}`);
}

Try / catch

try {
  startOAuthFlow(config);
} catch (e) {
  if (e.message.includes('must not include surrounding whitespace')) {
    config.oauth.redirectUri = config.oauth.redirectUri.trim();
    startOAuthFlow(config);
  } else throw e;
}

Prevention

When it happens

Trigger: Setting oauth.redirectUri (or equivalent config) with leading or trailing spaces, e.g. copied from docs with a trailing space, newline from a heredoc/env var, or padding added by an editor — then starting the OAuth flow via resolveCallbackOptions/redirectUri.

Common situations: Copy-pasting a redirect URI from documentation or a browser address bar with a trailing space; environment variables that absorbed a newline; JSON/YAML configs with accidental whitespace around the string value.

Related errors


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