can1357/oh-my-pi · critical · SearchProviderError

Refusing to send official Codex OAuth credentials to custom

Error message

Refusing to send official Codex OAuth credentials to custom endpoint ${transport.baseUrl}. Configure an API key for provider "openai-codex".

What it means

When a custom Codex endpoint is configured, sending official OpenAI Codex OAuth credentials (ChatGPT-account tokens) to a third-party URL would leak privileged credentials, so searchCodex throws a SearchProviderError unless an API key for provider "openai-codex" (or a command-backed key) is available. Command-backed keys take priority over AuthStorage origins, so they bypass this refusal.

Source

Thrown at packages/coding-agent/src/web/search/providers/codex.ts:763

	// request shape (responses-lite moves tools into an `additional_tools`
	// developer item), so the documented `web_search.filters.allowed_domains`
	// parameter cannot be assumed to survive it. Instead, re-emit directive
	// queries with the full Google-style operator syntax — the backing index
	// parses the classic operator set — and leave directive-free queries
	// byte-identical.
	const parsed = params.parsedQuery ?? parseSearchQuery(params.query);
	const query = parsed.hasDirectives ? formatQuery(parsed, GOOGLE_QUERY_SYNTAX) : params.query;

	let result: CodexSearchResult;
	if (transport.customEndpoint) {
		// ModelRegistry resolves command-backed provider keys before consulting
		// its AuthStorage, so a lower-priority OAuth origin is irrelevant when
		// that command source is configured.
		const credentialSource = params.modelRegistry?.authStorage ?? params.authStorage;
		const credentialOrigin = credentialSource.getCredentialOrigin("openai-codex");
		const hasCommandBackedKey = params.modelRegistry?.hasCommandBackedApiKey("openai-codex") === true;
		if (!hasCommandBackedKey && (credentialOrigin?.kind === "oauth" || credentialOrigin?.kind === "env")) {
			throw new SearchProviderError(
				"codex",
				`Refusing to send official Codex OAuth credentials to custom endpoint ${transport.baseUrl}. Configure an API key for provider "openai-codex".`,
			);
		}

		const resolverOptions = {
			sessionId: params.sessionId,
			baseUrl: transport.baseUrl,
			modelId: firstCandidate.modelId,
		};
		const keyOrResolver = params.modelRegistry
			? params.modelRegistry.resolver("openai-codex", resolverOptions)
			: params.authStorage.resolver("openai-codex", resolverOptions);
		result = await withAuth(
			keyOrResolver,
			accessToken =>
				runCodexSearchCandidates({
					auth: { accessToken },

View on GitHub (pinned to 9690622007)

Solutions

  1. Configure a dedicated API key for provider "openai-codex" for use with the custom endpoint.
  2. Set up a command-backed API key (hasCommandBackedApiKey) so the custom endpoint uses it instead of OAuth.
  3. Remove the custom endpoint override so the official endpoint is used with OAuth credentials.
  4. Ensure the credential origin is an API-key source rather than oauth/env if you intend to keep the custom endpoint.

Example fix

// before
customEndpoint = "https://gateway.corp.internal/v1"; // uses ChatGPT OAuth token -> refused
// after
// configure an API key for the gateway:
omp /login openai-codex --api-key sk-gateway-...
// or unset the custom endpoint to use official endpoint with OAuth
Defensive patterns

Strategy: validation

Validate before calling

const origin = authStorage.getCredentialOrigin("openai-codex");
const usingCustomEndpoint = transport.customEndpoint;
if (usingCustomEndpoint && (origin?.kind === "oauth" || origin?.kind === "env")) {
  throw new Error('Custom endpoint requires an API key for provider "openai-codex"');
}

Type guard

function isOAuthToCustomEndpointRefusal(e: unknown): e is SearchProviderError {
  return e instanceof SearchProviderError && e.message.startsWith("Refusing to send official Codex OAuth credentials");
}

Try / catch

try {
  return await searchCodex(params);
} catch (e) {
  if (isOAuthToCustomEndpointRefusal(e)) {
    // configure an API key, then retry once
    await configureApiKey("openai-codex");
    return searchCodex(params);
  }
  throw e;
}

Prevention

When it happens

Trigger: resolveCodexSearchTransport returns a custom endpoint (non-official baseUrl), the resolved credential origin for openai-codex is "oauth" or "env"-derived from OAuth storage, and modelRegistry.hasCommandBackedApiKey("openai-codex") is false.

Common situations: Pointing the Codex provider at a corporate proxy or OpenAI-compatible gateway while still logged in via `omp /login openai-codex`; environment credential resolution falling back to OAuth; migration from official login to a self-hosted endpoint without issuing an API key.

Related errors


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