{"record":{"id":"b58c2f90b8fdfd0e","repo":"jackwener/OpenCLI","slug":"code","errorCode":"${code}","errorMessage":"${message}","messagePattern":"\\$\\{message\\}","errorType":"error_code","errorClass":"CliError","httpStatus":null,"severity":"error","filePath":"clis/zsxq/utils.js","lineNumber":145,"sourceCode":"    }\n    if (!lastFailure) {\n        throw new CliError('FETCH_ERROR', 'No candidate endpoint returned JSON', `Checked endpoints: ${paths.join(', ')}`);\n    }\n    throw new CliError('FETCH_ERROR', lastFailure.error || 'Failed to fetch ZSXQ API', `Checked endpoints: ${paths.join(', ')}`);\n}\nexport function unwrapRespData(payload) {\n    const record = asRecord(payload);\n    if (!record) {\n        throw new CliError('PARSE_ERROR', 'Invalid ZSXQ API response');\n    }\n    if (record.succeeded === false) {\n        const code = typeof record.code === 'number' ? String(record.code) : 'API_ERROR';\n        const message = typeof record.info === 'string'\n            ? record.info\n            : typeof record.error === 'string'\n                ? record.error\n                : 'ZSXQ API returned an error';\n        throw new CliError(code, message);\n    }\n    return (record.resp_data ?? record.data ?? payload);\n}\nexport function getTopicsFromResponse(payload) {\n    const data = unwrapRespData(payload);\n    if (Array.isArray(data))\n        return data;\n    return pickArray(data.topics, data.list, data.records, data.items, data.search_result);\n}\nexport function getCommentsFromResponse(payload) {\n    const data = unwrapRespData(payload);\n    if (Array.isArray(data))\n        return data;\n    return pickArray(data.comments, data.list, data.items);\n}\nexport function getGroupsFromResponse(payload) {\n    const data = unwrapRespData(payload);\n    if (Array.isArray(data))","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/zsxq/utils.js#L127-L163","documentation":"When unwrapRespData sees payload.succeeded === false, it maps the API-level failure to a CliError whose code is the numeric record.code (as string) or the fallback 'API_ERROR', and whose message comes from record.info / record.error / a generic fallback. This converts ZSXQ's business-level errors (e.g. not-authed, not-found, rate-limit codes) into typed CLI errors.","triggerScenarios":"Any API wrapper call (via data()) where ZSXQ responds succeeded:false — e.g. code 401/415 for expired auth (info about re-login), invalid group/topic ids, or permission errors; the thrown message/code are whatever the API returned.","commonSituations":"Expired session returning ZSXQ's auth error codes; requesting a private group you lack access to; deleted topic ids; ZSXQ rate-limit codes.","solutions":["Match on the error code: re-login in the browser for auth-related codes (e.g. 401/415)","Verify the group_id/topic_id values you passed exist and are accessible","Slow down request frequency if the code indicates rate limiting","Catch CliError and branch on err.code to handle specific API codes programmatically"],"exampleFix":"// before\nconst data = await getData();\n// after\ntry {\n  const data = await getData();\n} catch (e) {\n  if (e.code === '401' || e.code === '415') await promptRelogin();\n  else throw e;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const data = await getData();\n} catch (e) {\n  if (e.code === '401' || e.code === '415') await reloginAndRetry();\n  else if (e.code === 'API_ERROR') console.error('ZSXQ API error:', e.message);\n  else throw e;\n}","preventionTips":["Branch on CliError.code to handle known ZSXQ codes explicitly","Refresh auth sessions proactively for scheduled jobs","Validate group/topic ids against accessible groups before calling the API","Throttle request rates to avoid limit-related API codes"],"tags":["api","business-error","error-code","zsxq"],"backgroundTag":"api-business-error","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}