jackwener/OpenCLI · error · CommandExecutionError

字幕条目缺少 subtitle_url 字段

Error message

字幕条目缺少 subtitle_url 字段

What it means

A CommandExecutionError thrown when the selected subtitle track object does not contain a subtitle_url property. The library picks the track matching kwargs.lang (or the first track) and requires subtitle_url to know where the CDN JSON subtitle file lives. This indicates the API returned malformed or unexpectedly shaped subtitle data.

Source

Thrown at clis/bilibili/subtitle.js:74

            throw new CommandExecutionError(`获取视频播放信息失败: ${payload.message} (${payload.code})`);
        }
        const needLoginSubtitle = payload.data?.need_login_subtitle === true;
        const subtitles = payload.data?.subtitle?.subtitles;
        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 };

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Drop the --lang option so the library falls back to subtitles[0] instead of a possibly malformed matching track.
  2. Re-run the command — transient API payloads sometimes omit fields.
  3. Check whether a Bilibili API update renamed subtitle_url (inspect the raw /player/wbi/v2 response).
  4. Update the CLI/library to a version matching the current API shape.

Example fix

// before
await run('bilibili subtitle', { url, lang: 'ai-zh' });
// after
await run('bilibili subtitle', { url }); // let it pick the first valid track
Defensive patterns

Strategy: validation

Validate before calling

// After receiving the API list yourself (or after a failure), verify entries:
const valid = Array.isArray(subtitles) && subtitles.some(s => s && typeof s === 'object' && 'subtitle_url' in s);

Type guard

const hasSubtitleUrl = (t) => !!t && typeof t === 'object' && 'subtitle_url' in t;

Try / catch

try {
  await run('bilibili subtitle', { url, lang });
} catch (e) {
  if (/subtitle_url/.test(e.message)) {
    return run('bilibili subtitle', { url }); // retry without lang filter
  }
  throw e;
}

Prevention

When it happens

Trigger: The chosen subtitles[i] entry lacks subtitle_url — e.g. the player API response shape changed, or the entry matched by kwargs.lang is a stub/metadata-only track.

Common situations: Passing a lang code that matches a track with no downloadable URL; Bilibili changing/renaming the subtitle_url field in an API update; mocking or cached API responses missing the field.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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