n8n-io/n8n · error · Error

Failed to list ${provider} models (status ${response.status}

Error message

Failed to list ${provider} models (status ${response.status})${body ? `: ${body.slice(0, 500)}` : ''}

What it means

The fallback branch of the model-listing request helper: the response is non-OK and NOT 401/403, so it's a transport/provider error (4xx/5xx). It reads up to 500 chars of the response body and throws an Error naming the provider and HTTP status, so the user can see the underlying failure rather than a generic 'models could not be loaded'.

Source

Thrown at packages/@n8n/ai-utilities/src/model-discovery/request.ts:26

	headers: Record<string, string>,
	options: ListModelsOptions,
	provider: string,
): Promise<unknown> {
	const fetchFn = options.fetch ?? globalThis.fetch;
	const response = await fetchFn(url, {
		method: 'GET',
		headers: { ...headers, ...options.headers },
	});
	if (!response.ok) {
		if (response.status === 401 || response.status === 403) {
			throw new UserError(
				"Models couldn't be loaded. Check that the selected credential is valid and has the required permissions, then try again.",
				{ shouldReport: false },
			);
		}

		const body = await response.text().catch(() => '');
		throw new Error(
			`Failed to list ${provider} models (status ${response.status})${body ? `: ${body.slice(0, 500)}` : ''}`,
		);
	}
	return await response.json();
}

/** Resolve the API base: caller override or the provider default, without a trailing slash. */
export function baseUrl(options: ListModelsOptions, fallback: string): string {
	return (options.baseURL ?? fallback).replace(/\/+$/, '');
}

export function bearerHeaders(options: ListModelsOptions): Record<string, string> {
	return { Authorization: `Bearer ${options.apiKey}` };
}

export function byName(a: ProviderModel, b: ProviderModel): number {
	return a.name.localeCompare(b.name);
}

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Read the status + body in the message: 429 → slow down / retry with backoff; 5xx → provider outage, retry later; 404 → fix baseURL.
  2. If using a custom baseURL, confirm it points at the provider's models endpoint.
  3. Retry transient failures; surface persistent ones to the provider's status page.
Defensive patterns

Strategy: retry

Type guard

function isModelListHttpError(e: unknown): boolean {
  return e instanceof Error && /Failed to list .* models \(status \d+\)/.test(e.message);
}

Try / catch

for (const delay of [1000, 3000, 10000]) {
  try {
    return await listModelsForProvider(provider, opts);
  } catch (e) {
    if (!isModelListHttpError(e)) throw e;
    if (/status 429|status 5\d\d/.test(e.message)) await new Promise((r) => setTimeout(r, delay));
    else throw e;
  }
}

Prevention

When it happens

Trigger: Provider returns 429 (rate limit), 500/502/503 (outage), 404 (wrong baseURL), 400 (malformed request), or a network-level non-OK status; a custom baseURL pointing to the wrong endpoint; provider model API temporarily down.

Common situations: Rate limiting on the models endpoint; provider outage; misconfigured baseURL override; proxy/gateway returning an unexpected status; region-specific endpoint unavailable.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/5cd037ea51a9f57c. Report an issue: GitHub.