can1357/oh-my-pi · error · Error
HTTPS loopback redirect URIs cannot reuse the same local por
Error message
HTTPS loopback redirect URIs cannot reuse the same local port; terminate TLS separately and forward to oauth.callbackPort
What it means
When an HTTPS loopback redirect URI is configured, the OAuth flow uses two ports: the HTTPS port from the redirect URI (fronted by a TLS terminator) and the plain-HTTP callbackPort where the library's local listener actually binds. If callbackPort equals the port in the redirect URI, the listener would collide with the terminator on the same port, so validation rejects it.
Source
Thrown at packages/coding-agent/src/mcp/oauth-flow.ts:170
function getUriPort(uri: URL): number {
if (uri.port !== "") return Number(uri.port);
return uri.protocol === "https:" ? 443 : 80;
}
function validateRedirectConfig(config: MCPOAuthConfig, redirectUri: string | undefined): void {
const parsed = parseRedirectUri(redirectUri);
if (parsed?.protocol !== "https:" || !isLoopbackHostname(parsed.hostname)) {
return;
}
if (config.callbackPort === undefined) {
throw new Error(
"HTTPS loopback redirect URIs require oauth.callbackPort to point at the local HTTP callback listener behind your TLS terminator",
);
}
if (config.callbackPort === getUriPort(parsed)) {
throw new Error(
"HTTPS loopback redirect URIs cannot reuse the same local port; terminate TLS separately and forward to oauth.callbackPort",
);
}
}
function resolveCallbackPort(callbackPort: number | undefined, redirectUri: string | undefined): number {
if (callbackPort !== undefined) return callbackPort;
const parsed = parseRedirectUri(redirectUri);
if (parsed?.protocol !== "http:" || !isLoopbackHostname(parsed.hostname)) {
return DEFAULT_PORT;
}
const port = getUriPort(parsed);
return Number.isFinite(port) && port > 0 ? port : DEFAULT_PORT;
}
function resolveCallbackPath(callbackPath: string | undefined, redirectUri: string | undefined): string {View on GitHub (pinned to 9690622007)
Solutions
- Choose a different port for oauth.callbackPort and configure the TLS terminator to forward the redirect port to it
- If you don't actually need TLS, change the redirect URI to http://localhost:<port>/... so no terminator/port split is required
- Pick an unused high port for the local listener to also avoid 'address in use' conflicts
Example fix
// before: same port on both sides
"oauth": { "redirectUri": "https://localhost:8443/auth/callback", "callbackPort": 8443 }
// after: terminator on 8443 forwards to listener on 1455
"oauth": { "redirectUri": "https://localhost:8443/auth/callback", "callbackPort": 1455 } Defensive patterns
Strategy: validation
Validate before calling
const p = new URL(config.oauth.redirectUri);
if (p.protocol === 'https:' && config.oauth.callbackPort === p.port) {
throw new Error('oauth.callbackPort must differ from the https redirect port');
} Try / catch
try {
startOAuthFlow(config);
} catch (e) {
if (e.message.includes('cannot reuse the same local port')) {
throw new Error('Point oauth.callbackPort at a separate port the TLS terminator forwards to, not the redirect port');
} else throw e;
} Prevention
- Treat the https redirect port and callbackPort as two different services by design
- Pick callbackPort from an unused port range to avoid both collisions and 'address in use' errors
- Configure terminator forwarding (https:PORT -> http:callbackPort) and verify with curl before running the flow
- Never copy the redirect port into callbackPort
When it happens
Trigger: Setting oauth.redirectUri to https://localhost:<port>/... and oauth.callbackPort to the SAME <port> (e.g. both 8443) when resolving callback options via resolveCallbackOptions.
Common situations: Users setting callbackPort to the same value as the redirect port because they assumed they must match; copy-pasting the redirect port into callbackPort; not understanding the terminator-forward-to-listener topology.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- HTTPS loopback redirect URIs require oauth.callbackPort to p
- Unknown OAuth provider: ${provider}
- OAuth provider "${provider}" does not support token refresh
- ${name} path does not exist: ${trimmed}
- Alibaba Coding Plan
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/e5397202e9b5a046.
Report an issue: GitHub.