jackwener/OpenCLI · error · CommandExecutionError

获取到的视频播放信息对象不符合预期格式

Error message

获取到的视频播放信息对象不符合预期格式

What it means

The player/v2 endpoint returned something that is not a plain object (null, an array, or a non-object), so the code cannot read .code/.data from it. The library throws this CommandExecutionError instead of dereferencing undefined properties. It guards against Bilibili returning an unexpected payload shape (e.g. an HTML/JSON array interstitial or empty body parsed oddly).

Source

Thrown at clis/bilibili/subtitle.js:53

        }
        // --page 给定时用该集 cid(selectVideoPart 越界抛错);缺省取整集默认 cid(P1,旧行为)。
        const cid = selectedPage != null ? selectVideoPart(view?.data, selectedPage).cid : view?.data?.cid;
        if (!cid) {
            throw new CommandExecutionError(`无法从 view API 拿到 cid (bvid=${bvid})`);
        }
        // 2. 用带 Wbi 签名的 player/v2 拿字幕列表(之前 evaluate 里 fetch 因为没签名会 403)
        let payload;
        try {
            payload = await apiGet(page, '/x/player/wbi/v2', {
                params: { bvid, cid },
                signed: true,
            });
        }
        catch (err) {
            throw new CommandExecutionError(`获取视频播放信息失败: ${err?.message || err}`);
        }
        if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
            throw new CommandExecutionError('获取到的视频播放信息对象不符合预期格式');
        }
        if (payload.code !== 0) {
            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]

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry the command — transient interstitials often resolve on a second attempt
  2. Verify you are not behind a proxy/captive portal mangling responses to api.bilibili.com
  3. Log the raw payload (log in a debug run) to see what actually came back and adjust expectations
  4. Ensure the session is logged in; some content types return degenerate payloads when unauthenticated
Defensive patterns

Strategy: type-guard

Type guard

function isApiEnvelope(p) {
  return p != null && typeof p === 'object' && !Array.isArray(p) && typeof p.code === 'number';
}

Try / catch

try {
  await run(['bilibili', 'subtitle', bvid]);
} catch (e) {
  if (String(e.message).includes('不符合预期格式')) {
    // capture raw response for debugging; retry once in case of a transient interstitial
  } else throw e;
}

Prevention

When it happens

Trigger: payload from apiGet('/x/player/wbi/v2') is null, an Array, or typeof !== 'object' — i.e. the JSON parse succeeded but the top-level shape isn't the expected {code,data,...} envelope.

Common situations: Bilibili returning an error page/empty body that still parsed as JSON; a proxy or captive portal intercepting the response; API schema drift for certain content types; hitting an endpoint variant that returns a bare array.

Related errors


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