jackwener/OpenCLI · error · CommandExecutionError

字幕 URL 非法: ${finalUrl}

Error message

字幕 URL 非法: ${finalUrl}

What it means

A CommandExecutionError thrown when the resolved subtitle URL does not match /^https?:\/\// after protocol normalization. The library already prepends 'https:' to protocol-relative '//...' URLs, so a non-http(s) value means the API returned something unrecognizable as a fetchable URL.

Source

Thrown at clis/bilibili/subtitle.js:82

            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);
             // B站真实返回格式是 { font_size: 0.4, font_color: "#FFFFFF", background_alpha: 0.5, background_color: "#9C27B0", Stroke: "none", type: "json" , body: [{from: 0, to: 0, content: ""}] }
             if (Array.isArray(subJson?.body)) return { success: true, data: subJson.body };
             if (Array.isArray(subJson)) return { success: true, data: subJson };
             return { error: 'UNKNOWN_JSON', data: subJson };

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Inspect the raw player API response to see what subtitle_url actually contains.
  2. Re-run the request — if it's transient data corruption it may resolve.
  3. Update the library if Bilibili changed the URL format (e.g. new scheme).
  4. As a workaround, patch/normalize the URL yourself before fetch if you control the pipeline.

Example fix

// before
const finalUrl = targetSubUrl.startsWith('//') ? 'https:' + targetSubUrl : targetSubUrl;
// after
const finalUrl = targetSubUrl.startsWith('//')
  ? 'https:' + targetSubUrl
  : targetSubUrl.startsWith('/') ? 'https://api.bilibili.com' + targetSubUrl : targetSubUrl;
Defensive patterns

Strategy: validation

Validate before calling

const isHttpUrl = (u) => typeof u === 'string' && /^https?:\/\//i.test(u.startsWith('//') ? 'https:' + u : u);
if (!isHttpUrl(track.subtitle_url)) throw new Error('bad subtitle url');

Type guard

const isHttpUrl = (u) => typeof u === 'string' && /^https?:\/\//i.test(u);

Try / catch

try {
  await run('bilibili subtitle', { url });
} catch (e) {
  if (/字幕 URL 非法/.test(e.message)) throw new Error(`Upstream returned invalid subtitle URL; raw response should be inspected: ${e.message}`);
  throw e;
}

Prevention

When it happens

Trigger: target.subtitle_url contains a non-URL string (e.g. a relative path, placeholder text, or corrupted value) that doesn't start with '//' or 'http(s)://'.

Common situations: Bilibili API schema changes; proxies or response interceptors mangling the URL field; bogus data from cached/intercepted responses.

Related errors


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