DIYgod/RSSHub · warning · Error

Bilibili browser mode returned unexpected video list API sta

Error message

Bilibili browser mode returned unexpected video list API status ${response.status()}

What it means

Thrown by waitForVideoListResponseFromVideoPage when the captured wbi/arc/search XHR response has an HTTP status other than 200. The response was matched and received on time, but Bilibili answered with an error status (commonly 403, 412, or 302 to a login/captcha page). It indicates the request reached the API but was rejected at the gateway layer before any JSON body was returned.

Source

Thrown at lib/routes/bilibili/video.ts:111

};

const getVideoListResponse = async (responsePromise: ReturnType<typeof waitForVideoListResponse>) => {
    const videoListResponseResult = await responsePromise;
    if ('error' in videoListResponseResult) {
        throw new Error(`Bilibili browser mode did not receive a video list response within ${browserResponseTimeout}ms: ${getErrorMessage(videoListResponseResult.error)}`);
    }

    return videoListResponseResult.response;
};

const waitForVideoListResponseFromVideoPage = async (page: Page, videoUrl: string): Promise<BrowserResponse> => {
    const videoListResponsePromise = waitForVideoListResponse(page);
    await navigateToVideoPage(page, videoUrl);

    const response = await getVideoListResponse(videoListResponsePromise);

    if (response.status() !== 200) {
        throw new Error(`Bilibili browser mode returned unexpected video list API status ${response.status()}`);
    }

    const contentType = response.headers()['content-type'];
    if (!contentType?.includes('application/json')) {
        throw new Error(`Bilibili browser mode returned non-JSON response with status ${response.status()}; BILIBILI_COOKIE_* may be required`);
    }

    return response;
};

async function applyCookie(page: Page, cookie: string) {
    const cookies = cookie
        .split(';')
        .map((item) => item.trim())
        .filter(Boolean)
        .map((item) => {
            const equalIndex = item.indexOf('=');
            if (equalIndex <= 0) {

View on GitHub (pinned to bed535e087)

Solutions

  1. Set BILIBILI_COOKIE_{uid} (or any BILIBILI_COOKIE_*) so applyCookie injects the session before navigation.
  2. Identify the status: 412/403 = anti-crawler (slow down, rotate IP/account), 302/3xx = login redirect (cookie missing/expired).
  3. Reduce request frequency; run RSSHub behind a residential IP or proxy that bilibili does not flag.
  4. Retry after a cooldown — gateway blocks are often transient.

Example fix

// before
if (response.status() !== 200) {
    throw new Error(`Bilibili browser mode returned unexpected video list API status ${response.status()}`);
}

// after (surface status text + url for diagnosis)
if (response.status() !== 200) {
    throw new Error(`Bilibili browser mode returned status ${response.status()} (${response.statusText()}) for ${response.url()}; set BILIBILI_COOKIE_* or retry`);
}
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight: confirm the wbi/arc/search endpoint answers 200 from your IP.
import got from '@/utils/got';
async function videoApiReachable(uid: string) {
  try {
    const r = await got(`https://api.bilibili.com/x/space/wbi/arc/search?mid=${uid}&ps=1&pn=1`);
    return r.statusCode === 200;
  } catch { return false; }
}

Type guard

// Narrow a Playwright response into a usable 200 JSON response.
function isOkJsonResponse(response: { status(): number; headers(): Record<string,string> }): boolean {
  return response.status() === 200 && (response.headers()['content-type'] ?? '').includes('application/json');
}

Try / catch

try {
  if (response.status() !== 200) throw new Error(`status ${response.status()}`);
} catch (e) {
  const m = e instanceof Error ? e.message : '';
  if (m.includes('412') || m.includes('403') || m.includes('302')) {
    // anti-crawler / login redirect — backoff and retry once with a fresh page
    await backoffRetry();
  }
  throw e;
}

Prevention

When it happens

Trigger: fetchVideoListFromBrowser(uid): the page navigated, the arc/search XHR fired, and Bilibili responded with e.g. 412 Precondition (risk control), 403 Forbidden, or a redirect to a login page — and that non-200 status is captured by waitForResponse.

Common situations: No BILIBILI_COOKIE_* set so the browser session is unauthenticated and bilibili blocks the API; RSSHub IP flagged by anti-crawler; bilibili returned a captcha interstitial; account/IP under temporary ban.

Related errors


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