{"record":{"id":"d4741e234368e413","repo":"jackwener/OpenCLI","slug":"bilibili-creator-comparison-returned-non-integer-m","errorCode":null,"errorMessage":"Bilibili creator comparison returned non-integer metric ${definition.key}","messagePattern":"Bilibili creator comparison returned non-integer metric (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/bilibili/creator-stats.js","lineNumber":131,"sourceCode":"    }\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: [\n        {\n            name: 'bvid',\n            type: 'string',","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/bilibili/creator-stats.js#L113-L149","documentation":"Count- and seconds-unit metrics must be safe integers; the value passed Number.isFinite/non-negative validation but is fractional (e.g. 3.5 plays) or exceeds Number.MAX_SAFE_INTEGER. The library rejects it because such values indicate scaling or type drift in the undocumented API rather than real counters.","triggerScenarios":"A count metric (play, like, comment, dm, fav, coin, share, total_new_attention_cnt) or the duration field is a non-integer finite number, e.g. an averaged float from a new API version, or a microsecond/millisecond duration causing non-integral seconds.","commonSituations":"Bilibili switches duration from seconds to milliseconds-fractional values; A/B rollouts return floating-point counters; large counts near MAX_SAFE_INTEGER from data aggregation bugs.","solutions":["Retry the command to rule out a transient bad payload.","Check the raw value's magnitude: if duration looks like milliseconds, the CLI needs a unit conversion.","Update the CLI to round or rescale if Bilibili legitimately changed the representation.","Use an older manuscript / different video to confirm whether it is data-specific."],"exampleFix":"// caller-side tolerant rounding\nconst raw = target.stat?.[def.key];\nconst value = Number.isFinite(raw) && raw >= 0 && !Number.isInteger(raw) ? Math.round(raw) : raw;","handlingStrategy":"validation","validationCode":"const raw = row?.stat?.[def.key];\nif (typeof raw === 'number' && Number.isFinite(raw) && raw >= 0 && (def.unit === 'count' || def.unit === 'seconds') && !Number.isSafeInteger(raw)) {\n    // fractional or overflowed counter: round or reject\n}","typeGuard":"function isSafeNonNegativeInt(v) {\n    return typeof v === 'number' && Number.isSafeInteger(v) && v >= 0;\n}","tryCatchPattern":"try {\n    const rows = await creatorStats(bvid);\n} catch (e) {\n    if (/non-integer metric/.test(e.message)) {\n        // fall back to Math.round of raw value or null\n    } else throw e;\n}","preventionTips":["Round fractional counters defensively before display","Check whether duration fields changed unit (ms vs s) after API updates","Retry once to rule out transient bad payloads","Keep CLI validators in sync with current API responses"],"tags":["bilibili","validation","integer","malformed-response"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}