{"record":{"id":"3baf32ef2546faa1","repo":"can1357/oh-my-pi","slug":"http-response-status-from-tagsurl","errorCode":null,"errorMessage":"HTTP ${response.status} from ${tagsUrl}","messagePattern":"HTTP (.+?) from (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/config/model-discovery.ts","lineNumber":485,"sourceCode":"\t\treturn null;\n\t}\n}\n\nexport async function discoverOllamaModels(\n\tproviderConfig: DiscoveryProviderConfig,\n\tctx: DiscoveryContext,\n): Promise<Model<Api>[]> {\n\tconst endpoint = normalizeOllamaBaseUrl(providerConfig.baseUrl);\n\tconst tagsUrl = `${endpoint}/api/tags`;\n\tconst headers = { ...(providerConfig.headers ?? {}) };\n\tconst customTimeoutMs = providerConfig.discovery.timeoutMs;\n\tconst payload = await withTimeoutSignal(discoveryProbeTimeoutMs(endpoint, 250, customTimeoutMs), async signal => {\n\t\tconst response = await ctx.fetch(tagsUrl, {\n\t\t\theaders,\n\t\t\tsignal,\n\t\t});\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`HTTP ${response.status} from ${tagsUrl}`);\n\t\t}\n\t\treturn (await response.json()) as { models?: Array<{ name?: string; model?: string }> };\n\t});\n\tconst entries = (payload.models ?? []).flatMap(item => {\n\t\tconst id = item.model || item.name;\n\t\treturn id ? [{ id, name: item.name || id }] : [];\n\t});\n\tconst metadataById = new Map(\n\t\tawait Promise.all(\n\t\t\tentries.map(\n\t\t\t\tasync entry =>\n\t\t\t\t\t[\n\t\t\t\t\t\tentry.id,\n\t\t\t\t\t\tawait discoverOllamaModelMetadata(ctx, endpoint, entry.id, headers, customTimeoutMs),\n\t\t\t\t\t] as const,\n\t\t\t),\n\t\t),\n\t);","sourceCodeStart":467,"sourceCodeEnd":503,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/config/model-discovery.ts#L467-L503","documentation":"discoverOllamaModels probes a local/remote Ollama server's `GET /api/tags` endpoint to enumerate installed models. When the HTTP response is not ok (any non-2xx status), it throws `Error(\"HTTP <status> from <tagsUrl>\")` because the model list cannot be read. The library treats any non-ok status as fatal for discovery rather than parsing an error body.","triggerScenarios":"Calling discoverOllamaModels (via discoverModelsByProviderType with discovery.type pointing at an Ollama baseUrl) when the Ollama server answers /api/tags with 404 (wrong path/older Ollama behind a proxy stripping /api), 403 (auth/proxy blocked), 500 (Ollama internal error), or 502/503 (reverse proxy up but Ollama down).","commonSituations":"Ollama not actually running on the configured port; a reverse proxy (nginx/caddy) forwarding to the wrong upstream; OLLAMA_ORIGINS/CORS proxies returning 403; corporate proxy intercepting localhost traffic; pointing baseUrl at something that is not Ollama (e.g. an LM Studio or vLLM endpoint that lacks /api/tags).","solutions":["Verify the Ollama server is running and `curl http://<host>:11434/api/tags` returns 200 with a models JSON list.","Correct the provider baseUrl in the models config so it points at the Ollama root (e.g. http://localhost:11434), not another OpenAI-compatible server.","If behind a proxy, ensure /api/* is forwarded to Ollama and no auth middleware blocks the request; add needed headers to the provider config.","Raise or adjust discovery.timeoutMs only after confirming the status is not caused by a slow cold-start; then retry discovery."],"exampleFix":"// before: baseUrl points at an OpenAI-compatible server without /api/tags\n{ \"provider\": \"ollama\", \"baseUrl\": \"http://localhost:8080/v1\", \"discovery\": { \"type\": \"ollama\" } }\n// after: point at the Ollama root\n{ \"provider\": \"ollama\", \"baseUrl\": \"http://localhost:11434\", \"discovery\": { \"type\": \"ollama\" } }","handlingStrategy":"try-catch","validationCode":"const res = await fetch(`${baseUrl.replace(/\\/$/, '')}/api/tags`);\nif (!res.ok) throw new Error(`Ollama unreachable: HTTP ${res.status} from ${baseUrl}/api/tags`);","typeGuard":"function isOllamaTagsPayload(v: unknown): v is { models?: Array<{ name?: string; model?: string }> } {\n  return typeof v === \"object\" && v !== null && (\"models\" in v ? Array.isArray((v as any).models) : true);\n}","tryCatchPattern":"try {\n  const models = await discoverOllamaModels(cfg, ctx);\n} catch (err) {\n  if (err instanceof Error && /^HTTP \\d+ from /.test(err.message)) {\n    const status = Number(err.message.match(/HTTP (\\d+)/)?.[1]);\n    logger.warn(\"Ollama discovery failed\", { status, baseUrl: cfg.baseUrl });\n    return staticFallbackModels;\n  }\n  throw err;\n}","preventionTips":["Health-check /api/tags with curl before wiring discovery into config.","Point the provider baseUrl at the Ollama root (default http://localhost:11434), not another server.","Audit any reverse proxy so /api/* reaches Ollama without auth interference.","Catch and log discovery errors with the status so failures degrade to a static model list."],"tags":["network","http","model-discovery","ollama"],"backgroundTag":"http-non-2xx-model-list","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}