jackwener/OpenCLI · error · ArgumentError

Bilibili video URL did not contain an exact case-sensitive B

Error message

Bilibili video URL did not contain an exact case-sensitive BVID

What it means

After host/scheme validation succeeds, parseBvidOrVideoUrl requires pathname to match /^\/video\/(BV[0-9A-Za-z]{10})\/?$/ exactly, case-sensitively. If the path doesn't contain an exact BVID segment, this ArgumentError is thrown. Note the BVID returned by this function preserves the case of the input.

Source

Thrown at clis/bilibili/utils.js:31

 * malformed input as a b23.tv network lookup.
 */
export function parseBvidOrVideoUrl(value) {
    const raw = String(value ?? '').trim();
    if (EXACT_BVID_RE.test(raw)) return raw;

    let parsed;
    try {
        parsed = new URL(raw);
    }
    catch {
        throw new ArgumentError('Expected an exact BVID or bilibili.com video URL, for example BV1xx411c7mD');
    }
    if (!VIDEO_HOSTS.has(parsed.hostname) || parsed.protocol !== 'https:' || parsed.username || parsed.password || parsed.port) {
        throw new ArgumentError('Expected a trusted HTTPS bilibili.com video URL without credentials or a custom port');
    }
    const match = parsed.pathname.match(/^\/video\/(BV[0-9A-Za-z]{10})\/?$/);
    if (!match) {
        throw new ArgumentError('Bilibili video URL did not contain an exact case-sensitive BVID');
    }
    return match[1];
}
/**
 * Resolve Bilibili short URL / short code to BV ID.
 * Supports: BV1MV9NBtENN, XYzsqGa, b23.tv/XYzsqGa, https://b23.tv/XYzsqGa
 */
export function resolveBvid(input) {
    const trimmed = String(input).trim();
    if (/^BV[A-Za-z0-9]+$/i.test(trimmed)) {
        return Promise.resolve(trimmed);
    }
    try {
        const parsed = new URL(trimmed);
        if (/(\.|^)bilibili\.com$/i.test(parsed.hostname)) {
            const match = parsed.pathname.match(/\/(?:video|bangumi\/play)\/(BV[A-Za-z0-9]+)/i);
            if (match) {
                return Promise.resolve(match[1]);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Use a /video/BV... URL whose BVID is exactly 12 chars: 'BV' + 10 alphanumerics
  2. Convert av-numbers to BV ids (or use a resolver that accepts av numbers)
  3. Remove trailing path segments after the BVID
  4. Check character-by-character that the BVID matches what bilibili.com shows (case-sensitive)

Example fix

// before
parseBvidOrVideoUrl('https://www.bilibili.com/bangumi/play/BV1xx411c7mD/');
// after
parseBvidOrVideoUrl('https://www.bilibili.com/video/BV1xx411c7mD/');
Defensive patterns

Strategy: validation

Validate before calling

function extractBvidFromUrl(v) {
  const m = String(v ?? '').match(/\/video\/(BV[0-9A-Za-z]{10})\/?(?:[?#].*)?$/);
  return m ? m[1] : null; // null => don't call parseBvidOrVideoUrl
}

Type guard

function hasBvidPath(v) {
  try { return /^\/video\/BV[0-9A-Za-z]{10}\/?$/.test(new URL(String(v)).pathname); }
  catch { return false; }
}

Try / catch

try {
  const bvid = parseBvidOrVideoUrl(url);
} catch (err) {
  if (err instanceof ArgumentError && /case-sensitive BVID/.test(err.message)) {
    console.error(`URL is not a /video/BV... page: ${url}`);
  } else throw err;
}

Prevention

When it happens

Trigger: URLs to other bilibili pages (space, bangumi/play, opus), /video/ URLs whose id is not a BV id (older av numbers), BVIDs with wrong length or lowercase 'bv' prefix, URLs with extra path segments or query strings in the pathname match failure (query is fine, but e.g. /video/BV1xx411c7mD/extra is not).

Common situations: Passing a bangumi/season link instead of a /video/ link; sharing mobile app links with extra tracking path segments; hand-transcribed BVIDs with a missing/extra character; passing av-number URLs (video/av170001).

Related errors


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