{"record":{"id":"6e5f09698c26a54e","repo":"jackwener/OpenCLI","slug":"pixiv-novel-returned-malformed-series-order","errorCode":null,"errorMessage":"Pixiv novel returned malformed series order","messagePattern":"Pixiv novel returned malformed series order","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/pixiv/novel.js","lineNumber":46,"sourceCode":"export function novelRowFromBody(body, id) {\n  const normalized = requireNovelBody(body, id);\n  const b = normalized.payload;\n  const identity = normalized.identity;\n  if (b.seriesNavData != null && (Array.isArray(b.seriesNavData) || typeof b.seriesNavData !== 'object')) {\n    throw new CommandExecutionError('Pixiv novel returned malformed series metadata');\n  }\n  const series = b.seriesNavData || {};\n  const seriesId = b.seriesId ?? series.seriesId ?? '';\n  const seriesTitle = b.seriesTitle ?? series.title ?? '';\n  if (seriesId !== '' && !/^\\d+$/.test(String(seriesId))) {\n    throw new CommandExecutionError('Pixiv novel returned malformed series ID');\n  }\n  if (seriesTitle !== '' && typeof seriesTitle !== 'string') {\n    throw new CommandExecutionError('Pixiv novel returned malformed series title');\n  }\n  const seriesOrder = series.order ?? b.seriesContentOrder ?? '';\n  if (seriesOrder !== '' && (!Number.isSafeInteger(seriesOrder) || seriesOrder < 1)) {\n    throw new CommandExecutionError('Pixiv novel returned malformed series order');\n  }\n  return {\n    novel_id: identity.novelId,\n    title: identity.title,\n    author: identity.userName,\n    user_id: identity.userId,\n    series_id: seriesId === '' ? '' : String(seriesId),\n    series_title: seriesTitle || '',\n    series_order: seriesOrder,\n    words: optionalCount(b.wordCount, 'word count'),\n    characters: optionalCount(b.characterCount ?? b.textCount, 'character count'),\n    bookmarks: optionalCount(b.bookmarkCount, 'bookmark count') || 0,\n    likes: optionalCount(b.likeCount, 'like count') || 0,\n    views: optionalCount(b.viewCount, 'view count') || 0,\n    tags: tagsToString(b.tags),\n    created: dateOnly(b.createDate),\n    url: `https://www.pixiv.net/novel/show.php?id=${identity.novelId}`,\n  };","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/pixiv/novel.js#L28-L64","documentation":"novelRowFromBody requires seriesOrder (seriesNavData.order or b.seriesContentOrder), when present, to be a safe integer >= 1. Zero, negative numbers, floats, strings, or overflow-size values indicate corrupted series ordering data, so the CLI throws CommandExecutionError rather than emitting a bogus series_order column.","triggerScenarios":"series.order is 0, negative, a decimal, a numeric string like \"3\", or exceeds Number.MAX_SAFE_INTEGER; only checked when the value is not ''.","commonSituations":"API returns 0-based order for a legacy series; a mirror serializes order as a string; JavaScript precision loss on very large order values from a crafted payload; fixtures using index 0.","solutions":["Inspect the raw response to see the exact seriesOrder value and type","If it is a numeric string, coerce with Number()/parseInt and re-validate before calling novelRowFromBody","Update the CLI to a version tolerant of the current Pixiv ordering format","Fix fixtures/callers to use 1-based safe integers for seriesContentOrder"],"exampleFix":"// before\nbody.seriesContentOrder = \"3\"; // string\n// after\nbody.seriesContentOrder = Number.parseInt(body.seriesContentOrder, 10); // 3","handlingStrategy":"validation","validationCode":"const ord = body?.seriesNavData?.order ?? body?.seriesContentOrder;\nif (ord !== undefined && ord !== '' &&\n    (!(Number.isSafeInteger(Number(ord)) || Number(ord) >= 1))) {\n  throw new Error(`bad series order: ${ord}`);\n}","typeGuard":"function isPositiveSafeInt(v) {\n  return Number.isSafeInteger(v) && v >= 1;\n}","tryCatchPattern":"try {\n  const row = novelRowFromBody(body, id);\n} catch (e) {\n  if (e.message.includes('malformed series order')) {\n    const n = Number.parseInt(body.seriesNavData?.order, 10);\n    if (Number.isSafeInteger(n) && n >= 1) body.seriesContentOrder = n;\n  } else throw e;\n}","preventionTips":["Coerce numeric strings to integers before validation","Convert 0-based orders to 1-based when adapting other data sources","Guard against precision loss by not round-tripping large order values through floats"],"tags":["pixiv","validation","series-order","type-error"],"backgroundTag":"api-response-schema-mismatch","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}