linshenkx/prompt-optimizer · error · APIError
Unexpected API response format
Error message
Unexpected API response format
What it means
Thrown by AnthropicAdapter.getModelsAsync when the response body from the /v1/models endpoint does not match the expected shape (a JSON object with a data array). The adapter successfully got an HTTP response but could not parse any models out of it, so it aborts with a generic format error instead of returning garbage.
Source
Thrown at packages/core/src/services/llm/adapters/anthropic-adapter.ts:138
// 检查返回格式
if (response && response.data && Array.isArray(response.data)) {
const models = response.data
.map((model: any) => {
// 使用 buildDefaultModel 为每个模型 ID 创建 TextModel 对象
// Anthropic API 返回的 model 对象包含: id, name, version, capabilities
return this.buildDefaultModel(model.id)
})
.sort((a, b) => a.id.localeCompare(b.id))
if (models.length === 0) {
throw new APIError('API returned empty model list')
}
console.log(`[AnthropicAdapter] Successfully fetched ${models.length} models`)
return models
}
throw new APIError('Unexpected API response format')
} catch (error: any) {
console.error('[AnthropicAdapter] Failed to fetch models:', error)
// 连接错误处理(包括跨域检测)
if (error.message && (error.message.includes('Failed to fetch') ||
error.message.includes('NetworkError') ||
error.message.includes('ECONNREFUSED') ||
error.message.includes('CORS'))) {
throw new APIError(`Network error: ${error.message}`)
}
// API 错误处理
if (error.status) {
throw new APIError(`Anthropic API error (${error.status}): ${error.message}`)
}
// 其他错误
throw errorView on GitHub (pinned to 3e677b1d9f)
Solutions
- Verify the base URL is the real Anthropic API (https://api.anthropic.com) or a gateway that faithfully implements GET /v1/models
- curl the endpoint manually: curl -H "x-api-key: $KEY" $BASE_URL/v1/models and inspect the JSON shape
- If using a proxy, fix or upgrade it so { data: [...] } is returned
- Handle the APIError in the caller and surface a fallback static model list
Example fix
// before
const models = await adapter.getModelsAsync()
// after
let models
try {
models = await adapter.getModelsAsync()
} catch (e) {
if (e instanceof APIError && /Unexpected API response format/.test(e.message)) {
models = FALLBACK_ANTHROPIC_MODELS
} else throw e
} Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
function isAnthropicModelsPayload(d: unknown): d is { data: unknown[] } {
return !!d && typeof d === 'object' && Array.isArray((d as any).data)
} Try / catch
try {
const models = await adapter.getModelsAsync()
} catch (e) {
if (e instanceof APIError && e.message === 'Unexpected API response format') {
// verify endpoint manually, fall back to static model list
} else throw e
} Prevention
- Only point baseURL at servers that implement Anthropic's /v1/models schema
- Smoke-test gateways with curl before wiring them into config
- Keep a hardcoded fallback model list for major providers
When it happens
Trigger: Calling getModelsAsync() against an endpoint that returns non-JSON or a different schema: a proxy/gateway HTML error page with 200 status, a base URL pointing at an OpenAI-compatible server rather than Anthropic's API, or an API version that changed the models payload.
Common situations: Misconfigured baseURL (e.g. https://api.openai.com with an Anthropic key), self-hosted gateways (one-api, litellm) that don't implement GET /v1/models the Anthropic way, corporate proxies returning HTML login pages.
Related errors
- Cloudflare model search returned an unexpected response form
- Unexpected API response format
- API returned empty model list
- Network error: ${error.message}
- Anthropic API error (${error.status}): ${error.message}
AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27).
Data as JSON: /api/errors/6a758b4f51c29be1.
Report an issue: GitHub.