{"record":{"id":"a6d9f62cff4fbabf","repo":"jackwener/OpenCLI","slug":"pixiv-novel-returned-malformed-label","errorCode":null,"errorMessage":"Pixiv novel returned malformed ${label}","messagePattern":"Pixiv novel returned malformed (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/pixiv/novel.js","lineNumber":9,"sourceCode":"import { cli, Strategy } from '@jackwener/opencli/registry';\nimport { ArgumentError, CommandExecutionError } from '@jackwener/opencli/errors';\nimport { pixivFetch } from './utils.js';\nimport { dateOnly, tagsToString } from './bookmark-utils.js';\n\nfunction optionalCount(value, label) {\n  if (value == null || value === '') return '';\n  if (!Number.isSafeInteger(value) || value < 0) {\n    throw new CommandExecutionError(`Pixiv novel returned malformed ${label}`);\n  }\n  return value;\n}\n\nfunction requireNovelBody(body, id) {\n  if (!body || Array.isArray(body) || typeof body !== 'object') {\n    throw new CommandExecutionError(`Pixiv novel ${id} returned malformed detail payload`);\n  }\n  const novelId = String(body.id ?? '').trim();\n  const title = String(body.title ?? '').trim();\n  const userName = String(body.userName ?? '').trim();\n  const userId = String(body.userId ?? '').trim();\n  if (!/^\\d+$/.test(novelId) || novelId !== id || !title || !userName || !/^\\d+$/.test(userId)) {\n    throw new CommandExecutionError(`Pixiv novel ${id} returned malformed detail payload`);\n  }\n  return { payload: body, identity: { novelId, title, userName, userId } };\n}\n","sourceCodeStart":1,"sourceCodeEnd":27,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/pixiv/novel.js#L1-L27","documentation":"optionalCount validates numeric fields from the Pixiv novel detail payload (e.g. bookmark/series counts). If a field is present but is not a non-negative safe integer (or is negative), the library assumes the API response shape changed or the page returned junk, and throws CommandExecutionError with the field's label. null/'' are treated as legitimately absent and return ''.","triggerScenarios":"The Pixiv novel detail endpoint (fetched via pixivFetch) returns a payload where a count field is a string, float, boolean, or negative number instead of a non-negative integer — e.g. HTML/error page parsed into the body, or a Pixiv API shape change.","commonSituations":"Pixiv schema changes after site updates; scraping a page that returned a login/captcha/error page so count fields are garbage; JSON field type drift (number became string).","solutions":["Re-run the command after confirming you are logged in and the page loads normally (an error/login page often yields malformed payloads).","Update this CLI library to the latest version in case Pixiv changed the response shape and a fix was released.","Inspect the raw payload returned for the novel ID to confirm which count field is malformed; if Pixiv changed the field type, patch optionalCount normalization (e.g. Number(value)) upstream."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"function isValidCount(v) {\n  return v == null || v === '' || (Number.isSafeInteger(v) && v >= 0);\n}\nif (!isValidCount(body.bookmarkCount)) console.warn('count field malformed — Pixiv payload shape may have changed');","typeGuard":"function isNonNegSafeInt(v) {\n  return typeof v === 'number' && Number.isSafeInteger(v) && v >= 0;\n}","tryCatchPattern":"try {\n  const row = await cli.pixiv.novelView({ id });\n} catch (e) {\n  if (/malformed/.test(e.message)) {\n    console.error('Pixiv returned an unexpected payload (schema change or error page). Check login state, retry, or update the library.');\n  } else throw e;\n}","preventionTips":["Keep the library updated so scraper fixes for Pixiv schema changes land quickly.","Ensure a valid authenticated session before scraping — error/login pages produce malformed payloads.","Log raw payloads on failure to identify which count field changed type."],"tags":["pixiv","scraping","schema-validation","response-shape"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}