{"record":{"id":"c1b214cc4cf667b9","repo":"jackwener/OpenCLI","slug":"bilibili-creator-comparison-returned-a-malformed-m","errorCode":null,"errorMessage":"Bilibili creator comparison returned a malformed manuscript row","messagePattern":"Bilibili creator comparison returned a malformed manuscript row","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/bilibili/creator-stats.js","lineNumber":97,"sourceCode":"        ) {\n            throw error;\n        }\n        const detail = `${error?.message ?? error} ${error?.hint ?? ''}`.trim();\n        if (/abort|timed?\\s*out|timeout/i.test(detail)) {\n            throw new TimeoutError('Bilibili creator comparison', FETCH_TIMEOUT_SECONDS);\n        }\n        if (/HTTP\\s+(401|403)|登录|passport|\\/login\\b/i.test(detail)) {\n            throw new AuthRequiredError('member.bilibili.com', `Bilibili creator-center login is required: ${detail}`);\n        }\n        throw new CommandExecutionError(`Bilibili creator comparison request failed: ${detail}`);\n    }\n}\n\nfunction selectTarget(list, bvid) {\n    const matches = [];\n    for (const item of list) {\n        if (!isRecord(item) || typeof item.bvid !== 'string' || !/^BV[0-9A-Za-z]{10}$/.test(item.bvid)) {\n            throw new CommandExecutionError('Bilibili creator comparison returned a malformed manuscript row');\n        }\n        if (item.bvid === bvid) matches.push(item);\n    }\n    if (matches.length > 1) {\n        throw new CommandExecutionError(`Bilibili creator comparison returned duplicate rows for ${bvid}`);\n    }\n    if (matches.length === 0) {\n        throw new EmptyResultError(\n            `bilibili creator-stats ${bvid}`,\n            'The manuscript was not present in the latest 100 creator analytics rows; it may be older, not owned by this account, or not analyzed yet.',\n        );\n    }\n    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}","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/bilibili/creator-stats.js#L79-L115","documentation":"selectTarget iterates payload.data.list and whitelists each row: it must be a record with a string bvid matching /^BV[0-9A-Za-z]{10}$/. Because the endpoint is undocumented and unstable, any row failing that shape aborts the whole run with this CommandExecutionError instead of silently skipping bad rows. This is intentional strictness per the file's whitelist-based data contract.","triggerScenarios":"The compare endpoint's list contains an entry that is not an object, lacks bvid, or whose bvid is not a 12-char 'BV'+10 alphanumeric string (e.g. Bilibili adding ad/promoted rows, new row types, or a schema change).","commonSituations":"Bilibili injecting non-manuscript rows (ads, recommendations) into the analytics list; a schema change introducing new row shapes; fixtures drifting from production payloads.","solutions":["Log the offending row (JSON.stringify the item) to see the new shape and update the whitelist validation","Consider relaxing selectTarget to skip malformed rows instead of aborting, if Bilibili legitimately adds non-manuscript rows","Update the bvid regex if Bilibili alters the BV ID format","Refresh the sanitized probe fixtures and re-test against the live endpoint"],"exampleFix":"// before: abort on any bad row\nif (!isRecord(item) || typeof item.bvid !== 'string' || !/^BV[0-9A-Za-z]{10}$/.test(item.bvid)) {\n    throw new CommandExecutionError('...malformed manuscript row');\n}\n\n// after: skip non-conforming rows\nif (!isRecord(item) || typeof item.bvid !== 'string' || !/^BV[0-9A-Za-z]{10}$/.test(item.bvid)) {\n    continue;\n}","handlingStrategy":"validation","validationCode":"function rowLooksValid(item) {\n  return item && typeof item === 'object' && !Array.isArray(item) && typeof item.bvid === 'string' && /^BV[0-9A-Za-z]{10}$/.test(item.bvid);\n}\n// fetch the list first and assert every row passes rowLooksValid before processing","typeGuard":"function isManuscriptRow(item) {\n  return Boolean(item) && typeof item === 'object' && !Array.isArray(item) && typeof item.bvid === 'string' && /^BV[0-9A-Za-z]{10}$/.test(item.bvid);\n}","tryCatchPattern":"try {\n  const rows = await runCommand();\n} catch (e) {\n  if (/malformed manuscript row/.test(e.message)) {\n    // log raw list JSON; either update the whitelist or relax to skip-and-continue\n  } else throw e;\n}","preventionTips":["Keep the row whitelist in sync with observed live payloads (probe fixtures)","Log the offending row JSON on failure to speed up schema-drift diagnosis","Consider tolerating unknown extra row types instead of failing the entire run","Track Bilibili changes to the undocumented compare endpoint"],"tags":["bilibili","schema-validation","api-contract","data-integrity"],"backgroundTag":"api-response-schema-changed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}