{"record":{"id":"bc6fec4f10da793a","repo":"jackwener/OpenCLI","slug":"label-returned-a-malformed-flag","errorCode":null,"errorMessage":"${label} returned a malformed flag","messagePattern":"(.+?) returned a malformed flag","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/bilibili/video.js","lineNumber":23,"sourceCode":"function requireObject(value, label) {\n  if (!value || typeof value !== 'object' || Array.isArray(value)) {\n    throw new CommandExecutionError(`${label} returned a malformed payload`);\n  }\n  return value;\n}\n\nfunction unwrapBrowserResult(value) {\n  if (value && typeof value === 'object' && typeof value.session === 'string' && Object.hasOwn(value, 'data')) {\n    return value.data;\n  }\n  return value;\n}\n\nfunction readOptionalFlag(value, label) {\n  if (value == null) return false;\n  if (typeof value === 'boolean') return value;\n  if (typeof value === 'number') return value !== 0;\n  throw new CommandExecutionError(`${label} returned a malformed flag`);\n}\n\nfunction readOptionalString(value, label) {\n  if (value == null) return '';\n  if (typeof value === 'string') return value;\n  throw new CommandExecutionError(`${label} returned a malformed string`);\n}\n\ncli({\n  site: 'bilibili',\n  name: 'video',\n    access: 'read',\n  description: 'Get Bilibili video metadata (title, author, duration, stats, etc.)',\n  strategy: Strategy.COOKIE,\n  args: [\n    { name: 'bvid', required: true, positional: true, help: 'BV ID, video URL, or b23.tv short link' },\n    { name: 'page', required: false, help: '分P 选集序号（从 1 开始）。多 P 视频指定某一集，title/cid 返回该集；缺省取整集默认（P1）' },\n  ],","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/bilibili/video.js#L5-L41","documentation":"readOptionalFlag coerces an optional boolean-ish flag from an API payload. If the value is neither null/undefined, boolean, nor number, it throws this CommandExecutionError instead of guessing — protecting the rights/rightsPay/rightsUgcPay/rightsArcPay/upowerExclusive/payPreview outputs from garbage values.","triggerScenarios":"A Bilibili video rights field (e.g. pay, ugc_pay, arc_pay, upower_exclusive, pay_preview) arrives as a string like \"0\"/\"true\" or an object instead of a number/boolean — a schema drift or unexpected field type in the API response.","commonSituations":"Bilibili changes a rights field from numeric to string; a new experimental field type appears in the payload; scraping/middleware converts numbers to strings.","solutions":["Inspect the raw API response for the affected rights field to confirm its actual type","Loosen the parser to coerce numeric strings (Number(value)) before validation","Catch the error in the command handler and report the field as unknown rather than failing the whole command","Report/patch the schema change in clis/bilibili/video.js"],"exampleFix":"// before\nif (typeof value === 'number') return value !== 0;\nthrow new CommandExecutionError(`${label} returned a malformed flag`);\n// after\nif (typeof value === 'number') return value !== 0;\nif (typeof value === 'string' && value.trim() !== '' && !Number.isNaN(Number(value))) return Number(value) !== 0;\nthrow new CommandExecutionError(`${label} returned a malformed flag`);","handlingStrategy":"type-guard","validationCode":"// pre-normalize numeric-string flags before passing on\nconst normalized = (v) => v == null || typeof v === 'boolean' || typeof v === 'number' ? v : Number(v);","typeGuard":"function isFlagLike(v) {\n  return v == null || typeof v === 'boolean' || (typeof v === 'number' && Number.isFinite(v));\n}","tryCatchPattern":"try { const rights = await getRights(bvid); }\ncatch (e) {\n  if (e instanceof CommandExecutionError && e.message.includes('malformed flag')) console.warn('Rights field had unexpected type; treating as unknown');\n  else throw e;\n}","preventionTips":["Treat rights fields as optional/unknown in downstream code","Compare raw payloads against expected schema after Bilibili updates","Coerce numeric strings defensively at the boundary","Keep a sample of raw responses for regression testing"],"tags":["type-mismatch","api","bilibili"],"backgroundTag":"unexpected-field-type","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}