{"record":{"id":"178b88d58c8b292d","repo":"jackwener/OpenCLI","slug":"boss-friend-list-response-did-not-include-zpdata-f","errorCode":null,"errorMessage":"Boss friend list response did not include zpData.friendList","messagePattern":"Boss friend list response did not include zpData\\.friendList","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/boss/utils.js","lineNumber":162,"sourceCode":"    // Auto-check auth unless caller opts out\n    if (!opts.allowNonZero && data.code !== 0) {\n        assertOk(data);\n    }\n    return data;\n}\n// ── Convenience helpers ─────────────────────────────────────────────────────\n/**\n * Fetch the boss friend (chat) list.\n */\nexport async function fetchFriendList(page, opts = {}) {\n    const pageNum = opts.pageNum ?? 1;\n    const jobId = opts.jobId ?? '0';\n    const url = `https://${BOSS_DOMAIN}/wapi/zprelation/friend/getBossFriendListV2.json?page=${pageNum}&status=0&jobId=${jobId}`;\n    const data = await bossFetch(page, url, { allowNonZero: opts.allowNonZero });\n    if (opts.allowNonZero && data.code !== 0) return data;\n    const list = data.zpData?.friendList;\n    if (!Array.isArray(list)) {\n        throw new CommandExecutionError('Boss friend list response did not include zpData.friendList');\n    }\n    return list;\n}\n/**\n * Fetch the recommended candidates (greetRecSortList).\n */\nexport async function fetchRecommendList(page) {\n    const url = `https://${BOSS_DOMAIN}/wapi/zprelation/friend/greetRecSortList`;\n    const data = await bossFetch(page, url);\n    const list = data.zpData?.friendList;\n    if (!Array.isArray(list)) {\n        throw new CommandExecutionError('Boss recommend response did not include zpData.friendList');\n    }\n    return list;\n}\n/**\n * Find a friend by encryptUid, searching through friend list and optionally greet list.\n * Returns null if not found.","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/boss/utils.js#L144-L180","documentation":"fetchFriendList expects a successful BOSS friend-list response to carry data.zpData.friendList as an array. When allowNonZero is false (or code was 0) but zpData.friendList is missing or not an array, the library throws CommandExecutionError — the API replied 'successfully' but with an unexpected shape, so its contract changed or the payload was truncated.","triggerScenarios":"getBossFriendListV2.json returning code 0 (or allowNonZero with code 0) but without zpData.friendList — e.g. BOSS renamed/reshaped the field, the response was a partially-empty object, or a captcha/limit payload shaped differently.","commonSituations":"BOSS front-end API version change altering zpData structure; running an outdated library version after a BOSS schema update; jobId/page combos returning empty bodies without the usual array; intermittent server-side truncation under load.","solutions":["Update the library to the latest version — BOSS periodically changes zpData shapes and the library tracks them.","Log the full response (OPENCLI_VERBOSE or manual page.evaluate of the URL) to inspect the actual payload shape.","Retry — transient truncation under server load can produce empty zpData.","Adjust query params (valid jobId, pageNum within range) and retry, since odd parameter combos may return atypical bodies.","If the shape consistently differs, patch fetchFriendList to read the new field or file an issue with the captured payload."],"exampleFix":"// before\nconst list = data.zpData?.friendList;\n// after\nconst list = data.zpData?.friendList ?? data.zpData?.result ?? [];  // tolerate renamed field","handlingStrategy":"type-guard","validationCode":"function hasFriendList(data) {\n  return !!data && typeof data === 'object' && Array.isArray(data.zpData?.friendList);\n}\nconst probe = await bossFetch(page, friendListUrl, { allowNonZero: true });\nif (probe.code === 0 && !hasFriendList(probe)) console.error('zpData shape changed; update the library.');","typeGuard":"function isFriendList(v) {\n  return typeof v === 'object' && v !== null && Array.isArray(v.zpData?.friendList);\n}","tryCatchPattern":"try {\n  const friends = await fetchFriendList(page);\n} catch (e) {\n  if (e instanceof CommandExecutionError && /zpData\\.friendList/.test(e.message)) {\n    const raw = await bossFetch(page, friendListUrl, { allowNonZero: true });\n    console.error('Unexpected payload:', JSON.stringify(raw).slice(0, 500));\n    return []; // or report for library update\n  }\n  throw e;\n}","preventionTips":["Keep the library updated; BOSS changes zpData shapes over time","Log full payloads with OPENCLI_VERBOSE to spot schema drift early","Retry transient truncations before treating them as schema changes","File an issue with the captured payload if the shape consistently differs"],"tags":["schema-mismatch","api-shape","friend-list","malformed-response"],"backgroundTag":"api-response-shape-mismatch","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}