{"record":{"id":"9f237bea65ed5da5","repo":"jackwener/OpenCLI","slug":"pixiv-user-novels-returned-mismatched-novel-detail","errorCode":null,"errorMessage":"Pixiv user novels returned mismatched novel detail payload for ${expectedId}","messagePattern":"Pixiv user novels returned mismatched novel detail payload for (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/pixiv/novels.js","lineNumber":25,"sourceCode":"  requirePixivId,\n  requirePixivPayloadObject,\n  requirePixivString,\n} from './utils.js';\nimport { dateOnly, tagsToString } from './bookmark-utils.js';\n\nfunction optionalCount(value, label, fallback = '') {\n  if (value == null || value === '') return fallback;\n  if (!Number.isSafeInteger(value) || value < 0) {\n    throw new CommandExecutionError(`Pixiv user novel item returned malformed ${label}`);\n  }\n  return value;\n}\n\nfunction userNovelRow(work, rank, expectedId) {\n  const item = requirePixivPayloadObject(work, 'Pixiv user novel item');\n  const id = requirePixivId(item.id, 'Pixiv user novel item');\n  if (id !== expectedId) {\n    throw new CommandExecutionError(`Pixiv user novels returned mismatched novel detail payload for ${expectedId}`);\n  }\n  const title = requirePixivString(item.title, 'Pixiv user novel item');\n  return {\n    rank,\n    title,\n    novel_id: id,\n    words: optionalCount(item.wordCount, 'word count'),\n    characters: optionalCount(item.textCount ?? item.characterCount, 'character count'),\n    bookmarks: optionalCount(item.bookmarkCount, 'bookmark count', 0),\n    tags: tagsToString(item.tags),\n    created: dateOnly(item.createDate),\n    url: `https://www.pixiv.net/novel/show.php?id=${id}`,\n  };\n}\n\nfunction requireProfileNovelIds(body) {\n  const payload = requirePixivPayloadObject(body, 'Pixiv user profile');\n  if (!payload.novels || Array.isArray(payload.novels) || typeof payload.novels !== 'object') {","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/pixiv/novels.js#L7-L43","documentation":"userNovelRow fetches/validates a novel detail item that is expected to correspond to a specific novel ID (expectedId). If requirePixivId(item.id) parses successfully but does not equal expectedId, the library throws because Pixiv returned the detail payload for a different novel than requested — continuing would attribute the wrong title/content to the ranked row. This is an integrity check on positional/identity alignment between the profile novel list and the detail responses.","triggerScenarios":"Calling the user-novels CLI when the detail payload order or content no longer matches the profile's novels map keys: e.g. the API returns works keyed/ordered differently than requested, a novel was deleted between listing and detail fetch, or the caller passes a mismatched expectedId to userNovelRow.","commonSituations":"Pixiv returning stale or reordered data (profile updated mid-run); caching layer mixing payloads across users; off-by-one in the caller's loop pairing rank/id with detail items; a novel made private/deleted after the ID list was obtained.","solutions":["Print both expectedId and the received id from the payload to confirm which novel mismatched","Re-fetch the profile novel ID list immediately before requesting details to avoid stale/deleted IDs","Pair detail payloads by their returned id (build a map id->item) instead of assuming positional correspondence","Clear any HTTP cache/proxy between you and the Pixiv API","If novel is genuinely gone, skip that rank/id instead of throwing"],"exampleFix":"// before\nrows = ids.map((id, i) => userNovelRow(works[i], i + 1, id));\n// after\nconst byId = new Map(works.map(w => [String(w.id), w]));\nrows = ids.flatMap((id, i) =>\n  byId.has(String(id)) ? [userNovelRow(byId.get(String(id)), i + 1, id)] : []\n);","handlingStrategy":"try-catch","validationCode":"const detail = await fetchNovelDetail(id);\nif (detail && String(detail.id) !== String(id)) {\n  console.warn(`Detail payload id ${detail.id} does not match requested ${id}; skipping`);\n}","typeGuard":"function matchesExpectedId(item, expectedId) {\n  return item != null && String(item.id) === String(expectedId);\n}","tryCatchPattern":"try {\n  rows.push(userNovelRow(work, rank, expectedId));\n} catch (err) {\n  if (String(err.message).includes('mismatched novel detail payload')) {\n    console.warn(`Skipping ${expectedId}: detail payload mismatch`);\n    continue;\n  }\n  throw err;\n}","preventionTips":["Pair detail payloads by returned id (map lookup) rather than array position","Re-fetch the profile ID list right before detail requests to avoid deleted/stale novels","Skip-and-log mismatched items instead of failing the whole run","Beware caches/proxies that could return a payload for a different novel"],"tags":["pixiv","cli","id-mismatch","api-payload"],"backgroundTag":"payload-id-mismatch","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}