jackwener/OpenCLI · error · AuthRequiredError

Bilibili ${label} API requires login or permission: ${messag

Error message

Bilibili ${label} API requires login or permission: ${message} (${payload.code})

What it means

The Bilibili API responded with valid JSON but a non-zero `code`, and isAuthLikeBilibiliError classified it as an auth problem (code -101 not logged in, -111 csrf/token invalid, -403 forbidden, or a message mentioning csrf/登录/账号/权限/forbidden/permission/login). The library maps this to AuthRequiredError so callers know cookies/login must be supplied rather than retrying blindly.

Source

Thrown at clis/bilibili/utils.js:233

/**
 * Bilibili write APIs return a JSON envelope `{ code, message, data }`. A non-zero
 * `code` carries either an auth/permission failure (login expired, CSRF rejected,
 * forbidden) or an application-level error (rate limit, validation, etc.). These
 * two helpers route the envelope to the right typed error so every write adapter
 * surfaces login problems as `AuthRequiredError`, not a generic execution error.
 */
export function isAuthLikeBilibiliError(code, message) {
    return code === -101 || code === -111 || code === -403 || /csrf|登录|账号|权限|forbidden|permission|login/i.test(String(message ?? ''));
}

export function requireOkPayload(payload, label) {
    if (!payload || typeof payload !== 'object' || Array.isArray(payload) || !Object.hasOwn(payload, 'code')) {
        throw new CommandExecutionError(`Bilibili ${label} API returned a malformed payload`);
    }
    if (payload.code !== 0) {
        const message = payload.message ?? 'unknown error';
        if (isAuthLikeBilibiliError(payload.code, message)) {
            throw new AuthRequiredError('bilibili.com', `Bilibili ${label} API requires login or permission: ${message} (${payload.code})`);
        }
        throw new CommandExecutionError(`Bilibili ${label} API failed: ${message} (${payload.code})`);
    }
    return payload.data;
}

/**
 * POST form-encoded params to a Bilibili API endpoint.
 * Runs inside the logged-in browser context and auto-attaches the bili_jct CSRF token,
 * which Bilibili requires on every authenticated write request.
 */
export async function apiPost(page, path, opts = {}) {
    const params = opts.params ?? {};
    const stringified = Object.fromEntries(Object.entries(params).map(([k, v]) => [k, String(v)]));
    const paramsJs = JSON.stringify(stringified);
    const urlJs = JSON.stringify(`https://api.bilibili.com${path}`);
    return page.evaluate(`
    async () => {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Refresh your Bilibili cookies (re-export SESSDATA and bili_jct from a logged-in browser) and pass them to the client.
  2. Ensure POST requests include the bili_jct CSRF token in the form data.
  3. Verify the account actually has permission for the target content (private/favorites/membership).
  4. Catch AuthRequiredError in your code and prompt the user to log in instead of retrying.

Example fix

// before
const page = await newPage(); // no cookies -> code -101
const nav = await getNavData(page);
// after
const ctx = await browser.newContext();
await ctx.addCookies([{ name: 'SESSDATA', value: process.env.BILI_SESSDATA, domain: '.bilibili.com', path: '/' },
                      { name: 'bili_jct', value: process.env.BILI_JCT, domain: '.bilibili.com', path: '/' }]);
const page = await ctx.newPage();
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight: verify cookies work before heavy calls
const nav = await (await fetch('https://api.bilibili.com/x/web-interface/nav', { headers: { cookie } })).json();
if (nav.code !== 0 || !nav.data?.isLogin) throw new Error('Bilibili login required: refresh SESSDATA/bili_jct');

Try / catch

try { const data = requireOkPayload(payload, 'history'); } catch (e) { if (e instanceof AuthRequiredError) { await promptLoginOrRefreshCookies(); } else throw e; }

Prevention

When it happens

Trigger: Calling a Bilibili API that requires login (history, favorites, self info, etc.) with no or expired SESSDATA cookie; missing or stale bili_jct CSRF token; accessing content you lack permission for (private video, region-locked, membership-only).

Common situations: Cookies expired after Bilibili rotated them or you logged out elsewhere; copying only SESSDATA without bili_jct for POST endpoints; running headless/CI without a cookie file; account risk-controlled by Bilibili.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/a403a2b9729192ef. Report an issue: GitHub.