jackwener/OpenCLI · error · AuthRequiredError

[风控拦截/未登录] 获取到的 subtitle_url 为空!请确保 CLI 已成功登录且风控未封锁此账号。

Error message

[风控拦截/未登录] 获取到的 subtitle_url 为空!请确保 CLI 已成功登录且风控未封锁此账号。

What it means

An AuthRequiredError thrown when the selected subtitle track has a subtitle_url field but its value is empty or whitespace after trimming. Bilibili deliberately returns an empty URL when the request is blocked by risk control (风控) or the session is not logged in, so this is a signal about account/session state, not data corruption.

Source

Thrown at clis/bilibili/subtitle.js:78

        if (!Array.isArray(subtitles)) {
            throw new CommandExecutionError('获取到的字幕列表对象不符合数组格式');
        }
        if (subtitles.length === 0) {
            if (needLoginSubtitle) {
                throw new AuthRequiredError('bilibili.com', 'Bilibili subtitles are hidden behind login for this video. Please log in to bilibili.com in Chrome and retry.');
            }
            throw new EmptyResultError('bilibili subtitle', '此视频没有发现外挂或智能字幕。');
        }
        // 3. 选择目标字幕语言
        const target = kwargs.lang
            ? subtitles.find((s) => s.lan === kwargs.lang) || subtitles[0]
            : subtitles[0];
        if (!target || typeof target !== 'object' || !Object.hasOwn(target, 'subtitle_url')) {
            throw new CommandExecutionError('字幕条目缺少 subtitle_url 字段');
        }
        const targetSubUrl = typeof target.subtitle_url === 'string' ? target.subtitle_url.trim() : '';
        if (!targetSubUrl) {
            throw new AuthRequiredError('bilibili.com', '[风控拦截/未登录] 获取到的 subtitle_url 为空!请确保 CLI 已成功登录且风控未封锁此账号。');
        }
        const finalUrl = targetSubUrl.startsWith('//') ? 'https:' + targetSubUrl : targetSubUrl;
        if (!/^https?:\/\//i.test(finalUrl)) {
            throw new CommandExecutionError(`字幕 URL 非法: ${finalUrl}`);
        }
        // 4. 解析并拉取 CDN 的 JSON 文件
        const fetchJs = `
      (async () => {
         const url = ${JSON.stringify(finalUrl)};
         const res = await fetch(url);
         const text = await res.text();

         if (text.startsWith('<!DOCTYPE') || text.startsWith('<html')) {
            return { error: 'HTML', text: text.substring(0, 100), url };
         }

         try {
             const subJson = JSON.parse(text);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Open bilibili.com in Chrome and log in, then retry the CLI (it drives the same Chrome profile).
  2. Wait and retry later if you hit risk control from too many rapid requests.
  3. Reduce request rate / batch size, or switch to a residential IP instead of VPN/datacenter.
  4. Log out and back in to refresh cookies if the session is stale.
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check: ensure a Chrome profile logged into bilibili.com exists before invoking the CLI.

Try / catch

try {
  await run('bilibili subtitle', { url });
} catch (e) {
  if (e.name === 'AuthRequiredError' || /风控|未登录/.test(e.message)) {
    await backoff(60_000);
    return run('bilibili subtitle', { url }); // after login/cool-down
  }
  throw e;
}

Prevention

When it happens

Trigger: subtitle_url is '' or non-string (null) on the chosen track — typically when the CLI's Chrome session is not logged into bilibili.com or the account/IP is rate-limited or flagged by Bilibili's risk-control system.

Common situations: Running the CLI without having logged into bilibili.com in Chrome; scraping many videos quickly and triggering rate limiting; using a datacenter IP or VPN that Bilibili blocks; expired login cookies.

Related errors


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