linshenkx/prompt-optimizer · error · APIError
API returned empty model list
Error message
API returned empty model list
What it means
Thrown by AnthropicAdapter.getModelsAsync when the Anthropic models endpoint responds successfully but maps to zero models (empty data array). The adapter treats an empty model list as an API-level error (APIError) rather than returning [], because an authenticated Anthropic account should always expose at least the default models.
Source
Thrown at packages/core/src/services/llm/adapters/anthropic-adapter.ts:131
*/
public async getModelsAsync(config: TextModelConfig): Promise<TextModel[]> {
const client = this.createClient(config)
try {
const response = await client.models.list()
// 检查返回格式
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}`)
}
View on GitHub (pinned to 3e677b1d9f)
Solutions
- Log the raw API response body to verify the expected { data: [{ id, ... }] } shape
- Update the adapter or SDK to the latest version if Anthropic changed the response schema
- If using a proxy/gateway, confirm it forwards the models endpoint unmodified
- Fall back to a hardcoded default model list when this error is caught
Example fix
// before
const models = await adapter.getModelsAsync()
// after
let models
try {
models = await adapter.getModelsAsync()
} catch (e) {
if (e instanceof APIError && /empty model list/.test(e.message)) {
models = [adapter.buildDefaultModel('claude-3-5-sonnet')]
} else throw e
} Defensive patterns
Strategy: fallback
Validate before calling
null
Type guard
null
Try / catch
try {
models = await adapter.getModelsAsync()
} catch (e) {
if (e instanceof APIError && e.message.includes('empty model list')) {
models = [/* hardcoded fallback models */]
} else {
throw e
}
} Prevention
- Log raw provider responses to detect schema drift early
- Pin the adapter/SDK version and test getModelsAsync after upgrades
- Maintain a hardcoded fallback model list for critical paths
When it happens
Trigger: Calling getModelsAsync when the API response's data array is empty after mapping/filtering — e.g. an unexpected response schema where model.id extraction yields nothing, a filtered proxy/enterprise endpoint, or a malformed 200 response.
Common situations: API response shape changed after an Anthropic API version bump (fields renamed, so mapping produces nothing); requests routed through a gateway that returns an empty list; a broken interceptor stripping the data field.
Related errors
- Text comparison calculation failed: ${errorMessage}
- GENERATION_FAILED
- GENERATION_FAILED
- Unexpected API response format
- Network error: ${error.message}
AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27).
Data as JSON: /api/errors/5665e4811d9f6caf.
Report an issue: GitHub.