router-for-me/CLIProxyAPI · error
models request failed with status %d: %s
Error message
models request failed with status %d: %s
What it means
fetchModels in cmd/fetch_codex_models/main.go performs GET on the Codex models endpoint and, when the HTTP status is outside 2xx, returns `models request failed with status %d: %s` including the trimmed response body. The wrapped body usually distinguishes auth failure (401/403), bad client version (400), rate limiting (429), or upstream outage (5xx).
Source
Thrown at cmd/fetch_codex_models/main.go:274
httpClient.Transport = transport
}
}
httpResp, errDo := httpClient.Do(httpReq)
if errDo != nil {
return nil, 0, errDo
}
bodyBytes, errRead := io.ReadAll(httpResp.Body)
if errClose := httpResp.Body.Close(); errClose != nil && errRead == nil {
errRead = errClose
}
if errRead != nil {
return nil, 0, errRead
}
if httpResp.StatusCode < http.StatusOK || httpResp.StatusCode >= http.StatusMultipleChoices {
return nil, 0, fmt.Errorf("models request failed with status %d: %s", httpResp.StatusCode, strings.TrimSpace(string(bodyBytes)))
}
count, errCount := countModels(bodyBytes)
if errCount != nil {
return nil, 0, errCount
}
return bodyBytes, count, nil
}
func codexModelsURL(clientVersion string) (string, error) {
u, err := url.Parse(codexModelsBaseURL + codexModelsPath)
if err != nil {
return "", err
}
if strings.TrimSpace(clientVersion) != "" {
q := u.Query()
q.Set("client_version", strings.TrimSpace(clientVersion))
u.RawQuery = q.Encode()View on GitHub (pinned to 78f0c4079e)
Solutions
- Read the status code and embedded body in the error message: 401/403 -> fix credentials (re-login); 400 -> correct the client version; 429 -> wait and retry; 5xx -> retry later.
- Confirm the auth file refreshes cleanly (the tool refreshes automatically; failure surfaces as errors 45/46 first).
- Pass the client version of a current Codex CLI release via the flag/config the tool exposes.
- If behind a proxy, ensure proxy env vars reach the tool and the proxy permits chatgpt.com/backend-api endpoints.
Defensive patterns
Strategy: retry
Type guard
func isModelsHTTPStatusError(err error) bool {
return err != nil && strings.Contains(err.Error(), "models request failed with status")
}
func modelsStatus(err error) int { /* parse the %d from the message */ } Try / catch
body, count, err := fetchModels(ctx, auth, token, ver)
if isModelsHTTPStatusError(err) {
switch modelsStatus(err) {
case 401, 403: relogin()
case 429: time.Sleep(backoff); retry()
default: logAndAbort(err)
}
} Prevention
- Branch on the embedded status code instead of treating all failures identically.
- Rate-limit scripted fetches to stay under 429 thresholds.
- Keep credentials freshly refreshed before fetching models.
When it happens
Trigger: Access token expired or invalid (401); account not entitled to Codex models (403); wrong client_version query param (400); too many requests (429); upstream OpenAI endpoint error (5xx); corporate proxy returning its own error page with a non-2xx status.
Common situations: Running the fetch tool with stale credentials after failing to refresh; passing a --client-version that the endpoint no longer accepts; scripted/CI runs hammering the endpoint and hitting rate limits; region-blocked accounts.
Related errors
- response JSON does not contain models array
- missing access_token and refresh_token
- refresh response did not include access_token
- Codex live request body too large
- Realtime client secrets require an SDP or JSON call request
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/c0ba7e3045e0905e.
Report an issue: GitHub.