{"record":{"id":"403def6152dd39a0","repo":"Mintplex-Labs/anything-llm","slug":"models-modelsurl-returned-resp-status","errorCode":null,"errorMessage":"[models] ${modelsUrl} returned ${resp.status}","messagePattern":"\\[models\\] (.+?) returned (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"open-computer/services/interface-service/routes/api.js","lineNumber":166,"sourceCode":"  app.get(\"/api/v1/models\", async (req, res) => {\n    const baseUrl =\n      req.query.base_url || settings.OPENAI_BASE_URL || \"https://api.openai.com/v1\";\n    const apiKey = req.query.api_key || settings.OPENAI_API_KEY;\n    if (!apiKey && baseUrl === \"https://api.openai.com/v1\")\n      return res.json({ models: [] });\n\n    const modelsUrl =\n      resolveBaseUrlForGuest(baseUrl).replace(/\\/+$/, \"\") + \"/models\";\n    console.log(`[models] Fetching ${modelsUrl} (from base_url=${baseUrl})`);\n    try {\n      const controller = new AbortController();\n      const timeout = setTimeout(() => controller.abort(), 5000);\n      const headers = {};\n      if (apiKey) headers[\"Authorization\"] = `Bearer ${apiKey}`;\n      const resp = await fetch(modelsUrl, { headers, signal: controller.signal });\n      clearTimeout(timeout);\n      if (!resp.ok) {\n        console.warn(`[models] ${modelsUrl} returned ${resp.status}`);\n        return res.json({ models: [] });\n      }\n      const body = await resp.json();\n      const models = (body.data || []).map((m) => m.id).sort();\n      console.log(\n        `[models] Found ${models.length} models: ${models.slice(0, 5).join(\", \")}${models.length > 5 ? \"...\" : \"\"}`,\n      );\n      res.json({ models });\n    } catch (err) {\n      console.error(`[models] Failed to fetch ${modelsUrl}: ${err.message}`);\n      res.json({ models: [] });\n    }\n  });\n\n  // ── Token usage ────────────────────────────────────────────────────────\n  // Proxy-reported tokens (from actual OpenAI usage fields) take precedence\n  // over the hypervisor's char-based estimates.  The proxy accumulates\n  // session-wide; task usage tracks per-agent-invocation tool activity.","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/3aec848f2885144aa8f1e53b9731a04310d5d558/open-computer/services/interface-service/routes/api.js#L148-L184","documentation":"The /api models route fetched {base_url}/models (Authorization bearer when a key is set, 5s AbortController timeout) and received a non-2xx status, so it logs the status and returns an empty model list rather than erroring. The UI will simply show no models to pick.","triggerScenarios":"base_url wrong shape (missing/extra /v1, pointing at a web page or the wrong host) so /models 404s; 401/403 when the key is wrong or required; provider 5xx or down; local server (Ollama etc.) not running when queried.","commonSituations":"Confusion between provider base URL conventions (with vs without /v1); reverse proxy returning 502 while the upstream restarts; expired API key; firewall blocking egress so a gateway error surfaces.","solutions":["curl the exact URL logged ([models] Fetching ...) with the same Authorization header and inspect the status/body.","Correct base_url for the provider's convention (most OpenAI-compatible APIs want .../v1 as the base).","Verify the API key is valid and has model-listing permission.","Confirm the provider/local server is up and reachable from the service (not just from your workstation)."],"exampleFix":"# before\nOPENAI_BASE_URL=https://api.example.com\n\n# after (OpenAI-compatible providers expose /v1/models)\nOPENAI_BASE_URL=https://api.example.com/v1","handlingStrategy":"validation","validationCode":"// Preflight the models endpoint when saving provider settings:\nconst resp = await fetch(`${baseUrl.replace(/\\/+$/, '')}/models`, {\n  headers: apiKey ? { Authorization: `Bearer ${apiKey}` } : {},\n  signal: AbortSignal.timeout(5000),\n});\nif (!resp.ok) throw new Error(`provider /models returned ${resp.status} — check base_url and key`);","typeGuard":null,"tryCatchPattern":"try { models = await fetchModels(baseUrl, apiKey); } catch { models = []; } // empty list is a config signal, not a crash","preventionTips":["Confirm the provider's base_url convention (usually ends in /v1).","Test /models with curl whenever credentials or proxies change.","Keep the AbortController timeout; treat empty model lists as a misconfiguration flag.","Ensure egress from the service host to the provider is allowed."],"tags":["llm","models-endpoint","base-url","http-error-status"],"backgroundTag":"llm-provider-api-error","analyzedSha":"3aec848f2885144aa8f1e53b9731a04310d5d558","analyzedAt":"2026-08-18T10:02:21.017Z","contentChangedAt":"2026-08-18T10:02:21.017Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}