mastra-ai/mastra · error · Error

Failed to fetch from models.dev: ${response.statusText}

Error message

Failed to fetch from models.dev: ${response.statusText}

What it means

The models.dev registry gateway fetches https://models.dev/api.json to sync provider/model metadata; the HTTP response was not ok. The error carries response.statusText. Until this sync succeeds, the gateway can't resolve provider configs, API key env vars, or model capabilities.

Source

Thrown at packages/core/src/llm/model/gateways/models-dev.ts:135

export class ModelsDevGateway extends MastraModelGateway {
  readonly id = 'models.dev';
  readonly name = 'models.dev';

  private providerConfigs: Record<string, ProviderConfig> = {};
  private attachmentCapabilities: AttachmentCapabilities = {};
  private temperatureCapabilities: TemperatureCapabilities = {};
  private structuredOutputCapabilities: StructuredOutputCapabilities = {};

  constructor(providerConfigs?: Record<string, ProviderConfig>) {
    super();
    if (providerConfigs) this.providerConfigs = providerConfigs;
  }

  async fetchProviders(): Promise<Record<string, ProviderConfig>> {
    const response = await fetch('https://models.dev/api.json');
    if (!response.ok) {
      throw new Error(`Failed to fetch from models.dev: ${response.statusText}`);
    }

    const data = (await response.json()) as ModelsDevResponse;

    // Reset capability maps so removed providers/models are not retained across syncs
    this.attachmentCapabilities = {};
    this.temperatureCapabilities = {};
    this.structuredOutputCapabilities = {};

    const providerConfigs: Record<string, ProviderConfig> = {};

    for (const [providerId, providerInfo] of Object.entries(data)) {
      // Skip excluded providers
      if (EXCLUDED_PROVIDERS.includes(providerId)) continue;
      // Skip non-provider entries (if any)
      if (!providerInfo || typeof providerInfo !== 'object' || !providerInfo.models) continue;

      // Use provider ID as-is (keep hyphens for consistency)

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Check statusText/network access: curl https://models.dev/api.json from the same environment.
  2. Retry with backoff — often transient outage or throttling.
  3. Provide providerConfigs manually (the constructor accepts providerConfigs) to skip reliance on the live fetch.
  4. Cache a previously fetched api.json locally and inject it in offline/CI environments.

Example fix

// before
const gw = new ModelsDevGateway();
await gw.fetchProviders(); // fails offline
// after
const cached = require('./models-dev-cache.json');
const gw = new ModelsDevGateway({ providerConfigs: cached });
Defensive patterns

Strategy: fallback

Validate before calling

const res = await fetch('https://models.dev/api.json');
if (!res.ok) throw new Error(`models.dev unreachable (HTTP ${res.status}) — prepare cached providerConfigs`);

Try / catch

let providers;
try {
  providers = await gw.fetchProviders();
} catch (e) {
  if (/Failed to fetch from models.dev/.test(e.message)) {
    providers = require('./models-dev-cache.json'); // last-known-good snapshot
  } else throw e;
}

Prevention

When it happens

Trigger: Calling fetchProviders() when models.dev returns non-2xx: service outage, CDN error, rate limiting, DNS/network failure, or a proxy returning 403/502.

Common situations: Corporate proxy or firewall blocking models.dev; offline/air-gapped environments; models.dev downtime; aggressive rate limiting on shared CI runners.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/fb37b28365f0e197. Report an issue: GitHub.