DIYgod/RSSHub · error · Error

Fortnite API responded with ${statusMessage} for ${apiUrl}

Error message

Fortnite API responded with ${statusMessage} for ${apiUrl}

What it means

After Playwright successfully receives a response, response.ok() is checked — it returns false for any HTTP status outside the 200–299 range. The Fortnite API returning a 4xx/5xx means the endpoint rejected the request (rate limited, unauthorized, not found, or server error). The status code and status text are joined into a single descriptive message.

Source

Thrown at lib/routes/fortnite/news.ts:65

    await page.route('**/*', (route) => {
        const request = route.request();
        request.resourceType() === 'document' ? route.continue() : route.abort();
    });

    // log manually (necessary for Playwright)
    logger.http(`Requesting ${apiUrl}`);
    let data;
    try {
        const response = await page.goto(apiUrl, {
            waitUntil: 'networkidle',
        });
        if (!response) {
            throw new Error(`No response received from ${apiUrl}`);
        }
        if (!response.ok()) {
            const statusText = response.statusText();
            const statusMessage = [response.status(), statusText].filter(Boolean).join(' ');
            throw new Error(`Fortnite API responded with ${statusMessage} for ${apiUrl}`);
        }
        const contentType = response.headers()['content-type'];
        if (!contentType?.includes('application/json')) {
            throw new Error(`Fortnite API returned non-JSON response with content-type ${contentType ?? 'unknown'}`);
        }

        data = await response.json();
    } finally {
        await page.close();
        await context.close();
    }

    const { blogList: list } = data;

    const items = await Promise.all(
        list.map((item) =>
            cache.tryGet(item.link, () =>
                Promise.resolve({

View on GitHub (pinned to bed535e087)

Solutions

  1. Check the numeric status in the message: 401/403 → auth/cookie issue, 404 → endpoint moved, 429 → rate limit, 5xx → upstream outage.
  2. Ensure the Playwright browser context is shared and not isolated per request so session cookies persist.
  3. Add the Fortnite API host to the allowed request types in the interceptor so auth/XHR subrequests succeed.
  4. Report or update the apiUrl if Epic changed the endpoint.

Example fix

// before
if (!response.ok()) {
    const statusText = response.statusText();
    const statusMessage = [response.status(), statusText].filter(Boolean).join(' ');
    throw new Error(`Fortnite API responded with ${statusMessage} for ${apiUrl}`);
}

// after
if (!response.ok()) {
    const statusText = response.statusText();
    const statusMessage = [response.status(), statusText].filter(Boolean).join(' ');
    if (response.status() === 429) {
        throw new Error(`Fortnite API rate-limited the request (429). Reduce request frequency.`);
    }
    throw new Error(`Fortnite API responded with ${statusMessage} for ${apiUrl}`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// cannot pre-validate a server-side status; pre-flight with a HEAD request
import ofetch from '@/utils/ofetch';
try {
  await ofetch.raw(apiUrl, { method: 'HEAD' });
} catch (e) { /* expect non-2xx, log for visibility */ }

Type guard

const isRateLimited = (status: number) => status === 429;

Try / catch

try {
  // ... page.goto + ok() check
} catch (e) {
  if (/429/.test((e as Error).message)) {
    await new Promise((r) => setTimeout(r, 5000)); // back off
  }
  throw e;
}

Prevention

When it happens

Trigger: Fortnite's API returns 401/403 when the request lacks required cookies or headers (Playwright must have completed the auth flow), 404 when the endpoint path changed, 429 when rate limited, or 5xx during an Epic Games outage. Because the route loads the API URL as a browser document, missing browser-side auth tokens cause 401/403.

Common situations: Epic Games rotating the API URL or adding new required query parameters; the Playwright context not retaining session cookies; hitting the API too frequently and triggering rate limits; regional blocks returning 451.

Related errors


AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12). Data as JSON: /api/errors/dcfa044593c30634. Report an issue: GitHub.