Login with ChatGPT
Reference

Error codes

Every ChatGPTAuthError code, the HTTP error shapes, and ChatGPTProxyError.

The SDK throws one error class from core and server code, and one from the browser proxy provider. HTTP routes return structured JSON errors.

ChatGPTAuthError

import { ChatGPTAuthError, isRefreshTokenInvalid } from "@opencoredev/loginwithchatgpt-core";

try {
  await auth.getModels(request);
} catch (error) {
  if (error instanceof ChatGPTAuthError) {
    error.code;   // machine-readable code below
    error.status; // upstream HTTP status, when there was one
    error.body;   // upstream body snippet, when there was one
  }
}
CodeThrown when
device_code_request_failedUpstream refused to issue a device code.
device_code_disabledThe device-code endpoint returned 404, so the flow is unavailable for this issuer/client.
authorization_pendingPolling continued past what the caller allowed.
authorization_expiredThe 15-minute device code ran out, or waitForDeviceTokens() was aborted.
token_exchange_failedExchanging the authorization code for tokens failed.
token_refresh_failedA refresh failed for a reason other than a dead token (network blip, 5xx). Usually retryable.
refresh_token_invalidOpenAI reported the refresh token as expired, reused, or invalidated. The session is dead. The handler deletes it and reports expired. Detect with isRefreshTokenInvalid(error).
not_authenticatedAn operation needed tokens and none exist.
invalid_tokenTokens lack a usable accountId.
token_export_disabledRaw token export was requested without dangerouslyAllowTokenExport.
refresh_token_export_disabledRefresh-token export was requested without dangerouslyAllowRefreshTokenExport.
network_errorThe upstream request itself failed (DNS, timeout, offline).
models_request_failedGET /models upstream call failed.
responses_request_failedThe proxied /responses upstream call failed.

HTTP error shapes

Returned by the handler routes:

StatusBodyRoute(s)
400{ "error": "invalid_responses_request", "message": "…" }/responses
400{ "error": "invalid_service_tier", "serviceTier": "…" } or { "error": "invalid_reasoning_effort", "reasoningEffort": "…" }/responses
401{ "error": "not_authenticated" }/models, /responses
403{ "error": "model_not_allowed", "model": "…" }/responses
403{ "error": "origin_not_allowed", "origin": "…" }all non-GET routes
404 / 405plain text, 405 includes an Allow headerunknown path / wrong method
413{ "error": "responses_request_too_large", "maxRequestBytes": … }/responses
429{ "error": "rate_limited", "retryAfterSeconds": … } with a retry-after header/responses
upstream status{ "error": "responses_request_failed", "status": …, "detail": "…" }/responses
upstream status or 502{ "models": [], "error": "<code>", "message": "…" }/models

ChatGPTProxyError

Thrown by the browser proxy provider's listModels() when your handler answers non-OK:

import { ChatGPTProxyError } from "@opencoredev/loginwithchatgpt-ai";

try {
  await chatgpt.listModels();
} catch (error) {
  if (error instanceof ChatGPTProxyError && error.status === 401) {
    // signed out; show the login button
  }
}

Streaming errors from /responses surface through the AI SDK's own error types instead (see Troubleshooting).

Troubleshooting covers the same failures organized by symptom instead of by code.

On this page