jackwener/OpenCLI · error · CommandExecutionError

Bilibili creator comparison returned out-of-range percentage

Error message

Bilibili creator comparison returned out-of-range percentage ${definition.key}

What it means

Percentage metrics (unit 'percent', stored by Bilibili as basis points where 10000 = 100%) exceeded 10_000, which is impossible for a real ratio. The library rejects values above the theoretical maximum to catch mis-scaled or corrupt API data before it is displayed as a percentage.

Source

Thrown at clis/bilibili/creator-stats.js:128

    const target = matches[0];
    if (!isRecord(target.stat)) {
        throw new CommandExecutionError(`Bilibili creator comparison returned malformed stat data for ${bvid}`);
    }
    return target;
}

function metricValue(target, definition) {
    const source = definition.source === 'target' ? target : target.stat;
    if (!Object.prototype.hasOwnProperty.call(source, definition.key)) {
        throw new CommandExecutionError(`Bilibili creator comparison omitted metric ${definition.key}`);
    }
    const raw = source[definition.key];
    if (raw === null) return null;
    if (typeof raw !== 'number' || !Number.isFinite(raw) || raw < 0) {
        throw new CommandExecutionError(`Bilibili creator comparison returned malformed metric ${definition.key}`);
    }
    if (definition.unit === 'percent' && raw > 10_000) {
        throw new CommandExecutionError(`Bilibili creator comparison returned out-of-range percentage ${definition.key}`);
    }
    if ((definition.unit === 'count' || definition.unit === 'seconds') && !Number.isSafeInteger(raw)) {
        throw new CommandExecutionError(`Bilibili creator comparison returned non-integer metric ${definition.key}`);
    }
    return definition.divisor ? raw / definition.divisor : raw;
}

cli({
    site: 'bilibili',
    name: 'creator-stats',
    description: '读取当前账号最近稿件的核心创作指标(需登录创作中心)',
    access: 'read',
    example: 'opencli bilibili creator-stats <bvid-or-video-url> -f json',
    domain: 'member.bilibili.com',
    strategy: Strategy.COOKIE,
    browser: true,
    navigateBefore: `${MEMBER_ORIGIN}/platform/home`,
    args: [

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry to rule out a transient corrupt response.
  2. Dump the raw value of the failing key from the compare endpoint to check its scale.
  3. If Bilibili changed the scale (e.g. now 0–1 float), update the CLI's divisor/limit accordingly.
  4. Report the mismatch upstream so the percent validation limit is adjusted.

Example fix

// before
if (definition.unit === 'percent' && raw > 10_000) throw ...;
// after (accept fraction scale too)
if (definition.unit === 'percent' && raw > 10_000 && raw <= 1 === false) throw ...;
// or normalize first: const rawBp = raw <= 1 ? raw * 10_000 : raw;
Defensive patterns

Strategy: validation

Validate before calling

const raw = row?.stat?.[def.key];
if (typeof raw === 'number' && def.unit === 'percent' && raw > 10_000) {
    // unexpected scale (basis points max 10000 = 100%): normalize or reject
}

Type guard

function isValidBasisPoints(v) {
    return typeof v === 'number' && Number.isFinite(v) && v >= 0 && v <= 10_000;
}

Try / catch

try {
    const rows = await creatorStats(bvid);
} catch (e) {
    if (/out-of-range percentage/.test(e.message)) {
        // re-fetch once; if persistent, report API scale change
    } else throw e;
}

Prevention

When it happens

Trigger: A percent-unit metric key (full_play_ratio, active_fans_rate, tm_rate, crash_rate, interact_rate, play_trans_fan_rate) has a raw basis-point value > 10000 in target.stat — e.g. Bilibili changed the scale (ratio as fraction 0-1 vs basis points) or the field is populated with a different quantity.

Common situations: Bilibili A/B tests a new scale for rate fields; a metric like crash_rate momentarily stores cumulative counts; corrupt cached responses from a proxy.

Related errors


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