{"record":{"id":"954f5acbdd6a70ed","repo":"jackwener/OpenCLI","slug":"bilibili-creator-comparison-returned-out-of-range","errorCode":null,"errorMessage":"Bilibili creator comparison returned out-of-range percentage ${definition.key}","messagePattern":"Bilibili creator comparison returned out-of-range percentage (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/bilibili/creator-stats.js","lineNumber":128,"sourceCode":"    const target = matches[0];\n    if (!isRecord(target.stat)) {\n        throw new CommandExecutionError(`Bilibili creator comparison returned malformed stat data for ${bvid}`);\n    }\n    return target;\n}\n\nfunction metricValue(target, definition) {\n    const source = definition.source === 'target' ? target : target.stat;\n    if (!Object.prototype.hasOwnProperty.call(source, definition.key)) {\n        throw new CommandExecutionError(`Bilibili creator comparison omitted metric ${definition.key}`);\n    }\n    const raw = source[definition.key];\n    if (raw === null) return null;\n    if (typeof raw !== 'number' || !Number.isFinite(raw) || raw < 0) {\n        throw new CommandExecutionError(`Bilibili creator comparison returned malformed metric ${definition.key}`);\n    }\n    if (definition.unit === 'percent' && raw > 10_000) {\n        throw new CommandExecutionError(`Bilibili creator comparison returned out-of-range percentage ${definition.key}`);\n    }\n    if ((definition.unit === 'count' || definition.unit === 'seconds') && !Number.isSafeInteger(raw)) {\n        throw new CommandExecutionError(`Bilibili creator comparison returned non-integer metric ${definition.key}`);\n    }\n    return definition.divisor ? raw / definition.divisor : raw;\n}\n\ncli({\n    site: 'bilibili',\n    name: 'creator-stats',\n    description: '读取当前账号最近稿件的核心创作指标（需登录创作中心）',\n    access: 'read',\n    example: 'opencli bilibili creator-stats <bvid-or-video-url> -f json',\n    domain: 'member.bilibili.com',\n    strategy: Strategy.COOKIE,\n    browser: true,\n    navigateBefore: `${MEMBER_ORIGIN}/platform/home`,\n    args: [","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/bilibili/creator-stats.js#L110-L146","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Retry to rule out a transient corrupt response.","Dump the raw value of the failing key from the compare endpoint to check its scale.","If Bilibili changed the scale (e.g. now 0–1 float), update the CLI's divisor/limit accordingly.","Report the mismatch upstream so the percent validation limit is adjusted."],"exampleFix":"// before\nif (definition.unit === 'percent' && raw > 10_000) throw ...;\n// after (accept fraction scale too)\nif (definition.unit === 'percent' && raw > 10_000 && raw <= 1 === false) throw ...;\n// or normalize first: const rawBp = raw <= 1 ? raw * 10_000 : raw;","handlingStrategy":"validation","validationCode":"const raw = row?.stat?.[def.key];\nif (typeof raw === 'number' && def.unit === 'percent' && raw > 10_000) {\n    // unexpected scale (basis points max 10000 = 100%): normalize or reject\n}","typeGuard":"function isValidBasisPoints(v) {\n    return typeof v === 'number' && Number.isFinite(v) && v >= 0 && v <= 10_000;\n}","tryCatchPattern":"try {\n    const rows = await creatorStats(bvid);\n} catch (e) {\n    if (/out-of-range percentage/.test(e.message)) {\n        // re-fetch once; if persistent, report API scale change\n    } else throw e;\n}","preventionTips":["Remember percent fields are basis points (100 = 1%) when interpreting values","Re-fetch to rule out one-off corrupt responses","Track Bilibili creator-center A/B changes to rate-field scaling","Clamp/normalize percent values in downstream consumers"],"tags":["bilibili","validation","out-of-range","percentage"],"backgroundTag":"value-out-of-range","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}