nextai-translator/nextai-translator · error · Error

Invalid API key

Error message

Invalid API key

What it means

LiteLLM's listModels() maps HTTP 401 or 403 from the GET /models request to 'Invalid API key'. The virtual-key/Bearer token passed in the Authorization header was rejected by the LiteLLM proxy. Called via the public models() wrapper.

Source

Thrown at src/common/engines/litellm.ts:37

            return []
        }
        const url = urlJoin(apiURL, '/v1/models')
        const fetcher = getUniversalFetch()
        const headers: Record<string, string> = {
            'Content-Type': 'application/json',
        }
        // A LiteLLM proxy usually requires a virtual/master key, but some run
        // without auth, so only send the header when a key is configured.
        if (apiKey) {
            headers['Authorization'] = `Bearer ${apiKey}`
        }
        const response = await fetcher(url, {
            method: 'GET',
            headers,
        })
        if (response.status !== 200) {
            if (response.status === 401 || response.status === 403) {
                throw new Error('Invalid API key')
            }
            if (response.status === 404) {
                throw new Error('Invalid API URL')
            }
            throw new Error(`Failed to list models: ${response.statusText}`)
        }
        const json = await response.json()
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        return json.data.map((model: any) => {
            return {
                id: model.id,
                name: model.id,
            }
        })
    }

    async getAPIModel(): Promise<string> {
        const settings = await getSettings()

View on GitHub (pinned to f57537ee4a)

Solutions

  1. Verify/generate a valid virtual key in the LiteLLM proxy admin UI and re-enter it in settings
  2. Test the key directly: curl -H 'Authorization: Bearer <key>' <proxy>/v1/models
  3. Confirm the key has access to the models route and the allowed-models list is not empty
  4. Check the configured LiteLLM proxy base URL matches your deployment

Example fix

// before
const models = await litellm.models('') // empty key → 401
// after
const key = settings.litellmApiKey?.trim()
if (!key) throw new Error('Set your LiteLLM virtual key in settings')
const models = await litellm.models(key)
Defensive patterns

Strategy: validation

Validate before calling

const key = apiKey?.trim()
if (!key) throw new Error('LiteLLM virtual key missing')
const probe = await fetch(`${proxyBase}/v1/models`, { headers: { Authorization: `Bearer ${key}` } })
if (probe.status === 401 || probe.status === 403) throw new Error('LiteLLM key rejected by proxy')

Type guard

function isNonEmptyKey(k: unknown): k is string {
  return typeof k === 'string' && k.trim().length > 0
}

Try / catch

try {
  const models = await litellm.models(apiKey)
} catch (e) {
  if (e instanceof Error && e.message === 'Invalid API key') {
    openSettings('LiteLLM proxy rejected the key — regenerate a virtual key in the proxy UI')
  } else { throw e }
}

Prevention

When it happens

Trigger: Calling listModels() (or models()) on the LiteLLM engine when the proxy responds 401/403: the LiteLLM virtual key is wrong, expired, deleted, lacks model access, or no Authorization header was sent at all.

Common situations: Admin rotated/deleted a virtual key in the LiteLLM proxy UI; key typed with trailing whitespace; key created without permissions for the /models route; pointing at a proxy that requires auth while settings have an empty key field.

Understand the failure class

Related errors


AI-assisted analysis of nextai-translator/nextai-translator@f57537ee4a (2026-08-31). Data as JSON: /api/errors/bb637f652c2725cb. Report an issue: GitHub.