{"record":{"id":"14b7bd9335e1d4ee","repo":"jackwener/OpenCLI","slug":"boss-geek-chat-list-response-did-not-include-zpdat","errorCode":null,"errorMessage":"Boss geek chat list response did not include zpData.friendList","messagePattern":"Boss geek chat list response did not include zpData\\.friendList","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/boss/utils.js","lineNumber":420,"sourceCode":"      } catch (_) {}\n      return '';\n    })()\n  `);\n    return result || '';\n}\n/**\n * Fetch the job-seeker chat list (brief info, no securityId).\n * Use fetchGeekFriendInfoList to enrich with securityId before calling chatmsg.\n */\nexport async function fetchGeekFriendLabelList(page, opts = {}) {\n    const labelId = opts.labelId ?? 0;\n    const encryptSystemId = opts.encryptSystemId ?? '';\n    const url = `https://${BOSS_DOMAIN}/wapi/zprelation/friend/geekFilterByLabel?labelId=${labelId}&encryptSystemId=${encodeURIComponent(encryptSystemId)}`;\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 geek chat list response did not include zpData.friendList');\n    }\n    return list;\n}\n/**\n * Enrich a batch of geek friends with full fields including securityId.\n * Processes in batches of 50 to avoid oversized request bodies.\n */\nexport async function fetchGeekFriendInfoList(page, friendIds = []) {\n    if (!friendIds.length) return [];\n    const BATCH_SIZE = 50;\n    const results = [];\n    for (let i = 0; i < friendIds.length; i += BATCH_SIZE) {\n        const batch = friendIds.slice(i, i + BATCH_SIZE).map(String);\n        const body = `friendIds=${batch.join(',')}`;\n        const data = await bossFetch(page, `https://${BOSS_DOMAIN}/wapi/zprelation/friend/getGeekFriendList.json`, {\n            method: 'POST',\n            body,\n        });","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/boss/utils.js#L402-L438","documentation":"fetchGeekFriendLabelList queries geekFilterByLabel and requires data.zpData.friendList to be an array of geek chat contacts. If the endpoint returns anything else (auth failure, error envelope, schema change) the library throws this CommandExecutionError rather than returning undefined. With opts.allowNonZero a non-zero code is returned instead of throwing, but a zero-code response still must contain friendList.","triggerScenarios":"Calling labelList when geekFilterByLabel returns code 0 but no zpData.friendList — session expired mid-run, label id invalid, anti-bot interception, or Boss renamed the field.","commonSituations":"Cookie expiry between commands; passing an invalid/removed labelId; WAPI returning an HTML challenge page parsed as JSON without friendList; upstream API schema change.","solutions":["Re-login to Boss直聘 and retry labelList","Verify the labelId passed to fetchGeekFriendLabelList is valid for this account","Log the raw response body to distinguish auth/challenge responses from schema changes","Retry later if the response shows rate-limiting/anti-bot interception"],"exampleFix":"// before\nconst list = data.zpData?.friendList;\nif (!Array.isArray(list)) throw new CommandExecutionError('...');\n// after\nif (data.code !== 0) throw new AuthRequiredError(BOSS_DOMAIN, `geekFilterByLabel code=${data.code}`);\nconst list = Array.isArray(data.zpData?.friendList) ? data.zpData.friendList : [];","handlingStrategy":"type-guard","validationCode":"const cookies = await page.getCookies({ url: `https://${BOSS_DOMAIN}` });\nif (!cookies.some(c => /^wt2$|_uid/i.test(c.name) && c.value)) throw new Error('Boss session missing');","typeGuard":"function hasFriendList(d) { return Array.isArray(d?.zpData?.friendList); }","tryCatchPattern":"try { const list = await fetchGeekFriendLabelList(page, { labelId }); }\ncatch (e) { if (e instanceof CommandExecutionError) { await relogin(page); return fetchGeekFriendLabelList(page, { labelId }); } throw e; }","preventionTips":["Validate labelId against labelList output before filtering","Re-authenticate when any Boss WAPI call returns code != 0","Keep batch/command sessions short to avoid mid-run expiry","Log failing response bodies to catch schema drift"],"tags":["boss-zhipin","api-response","missing-field","auth"],"backgroundTag":"api-response-missing-field","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}