mastra-ai/mastra · error · Error

HTTP ${response.status}: ${response.statusText}

Error message

HTTP ${response.status}: ${response.statusText}

What it means

makeHttpRequest() fetches the configured URL and throws 'HTTP <status>: <statusText>' when response.ok is false (any non-2xx status). The response body may contain more details, but this error surfaces the raw HTTP failure from the log ingestion endpoint.

Source

Thrown at packages/loggers/src/http/index.ts:82

  private async makeHttpRequest(data: any, retryCount = 0): Promise<Response> {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), this.timeout);

    try {
      const body = JSON.stringify({ logs: data });

      const response = await fetch(this.url, {
        method: this.method,
        headers: this.headers,
        body,
        signal: controller.signal,
      });

      clearTimeout(timeoutId);

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }

      return response;
    } catch (error) {
      clearTimeout(timeoutId);

      if (retryCount < this.retryOptions.maxRetries) {
        const delay = this.retryOptions.exponentialBackoff
          ? this.retryOptions.retryDelay * Math.pow(2, retryCount)
          : this.retryOptions.retryDelay;

        await new Promise(resolve => setTimeout(resolve, delay));
        return this.makeHttpRequest(data, retryCount + 1);
      }

      throw error;
    }
  }

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Read the status in the error: fix 401/403 by updating credentials/headers, fix 404 by correcting the endpoint URL.
  2. Implement retry with backoff for 429/5xx — the transport already has a timeout/abort mechanism you can build around.
  3. Verify the endpoint accepts the POSTed JSON shape (array of log entries) and Content-Type: application/json.

Example fix

// before: flush failures bubble up
const logger = new HttpTransport({ url: endpoint });
// after: catch and retry transient statuses
try {
  await logger.flush();
} catch (e) {
  if (/HTTP (429|5\d\d):/.test(e.message)) {
    await new Promise(r => setTimeout(r, 2000));
    await logger.flush();
  } else throw e;
}
Defensive patterns

Strategy: retry

Validate before calling

function assertReachableEndpoint(url) {
  const u = new URL(url);
  if (u.protocol !== 'https:' && u.protocol !== 'http:') throw new Error('Log endpoint must be http(s)');
}

Try / catch

try {
  await logger.flush();
} catch (e) {
  const m = /HTTP (\d{3}):/.exec(e.message);
  if (m && ['429','500','502','503','504'].includes(m[1])) {
    await backoffRetry(() => logger.flush(), 3); // exponential backoff
  } else {
    console.error('Log endpoint rejected request:', e.message);
  }
}

Prevention

When it happens

Trigger: HttpTransport flushing log entries to an endpoint that returns 404 (wrong path), 401/403 (bad auth), 429 (rate limit), or 5xx (server error).

Common situations: Expired/invalid API key for the log collector; endpoint URL changed or includes a typo; collector rate-limiting under heavy log volume; transient server outages during _flush.

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/eafa285a4c141e93. Report an issue: GitHub.