{"record":{"id":"f2854c4823711b7d","repo":"DIYgod/RSSHub","slug":"each-message","errorCode":null,"errorMessage":"each.message","messagePattern":"each\\.message","errorType":"exception","errorClass":"Error","httpStatus":503,"severity":"error","filePath":"lib/routes/sicau/jk.ts","lineNumber":96,"sourceCode":"            baseURL: 'https://jk.sicau.edu.cn/act/actInfo/v1.0.0',\n            headers: { 'x-access-token': token },\n            method: 'post',\n        });\n        const query = async (page: number) =>\n            await $post('/getUserSchoolActList', {\n                query: {\n                    gid: gidDict[gid],\n                    typeId: typeDict[typeId],\n                    sortType,\n                    page,\n                },\n            });\n\n        const res = await Promise.all([query(1), query(2)]);\n\n        for (const each of res) {\n            if (each.code !== '0') {\n                throw new Error(each.message);\n            }\n        }\n\n        const list: DataItem[] = [...res[0].content, ...res[1].content]\n            .filter((e) => e.statusName !== '待发学时')\n            .map((each) => ({\n                id: each.id,\n                guid: each.id,\n                title: each.title,\n                image: each.logo,\n            }));\n\n        const items = await Promise.all(\n            list.map((item) =>\n                cache.tryGet(String(item.id), async () => {\n                    const { code, message, content } = await $post(`/getActDetail?actId=${item.id}`);\n                    if (code === '0') {\n                        item.author = content.groupName;","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/sicau/jk.ts#L78-L114","documentation":"The SICAU second-class activities route issues two paginated queries in parallel and checks each response: if `each.code !== '0'` it throws `each.message`, propagating the upstream API's own error text. Code `'0'` is the SICAU API's success sentinel; any other value indicates a backend-side error (invalid gid/typeId, auth, rate limit).","triggerScenarios":"A request to /sicau/jk/... where the upstream `/getUserSchoolActList` endpoint returns a non-zero code on either page 1 or page 2. Common when `gidDict[gid]` or `typeDict[typeId]` resolves to an invalid upstream id, or the API token/session is missing.","commonSituations":"Invalid gid/typeId path parameters; upstream API changed its code semantics; SICAU enabled auth or geographic restrictions; transient backend error.","solutions":["Verify the `:gid` and `:typeId` path parameters against the documented values in lib/routes/sicau/jk.ts (check `gidDict` and `typeDict`).","Retry shortly to rule out transient upstream errors.","If the API contract changed, inspect the raw response to see the new error code/message and update the dicts accordingly."],"exampleFix":"// before\n/rsshub/sicau/jk/<bad-gid>/<bad-type>\n\n// after\n/rsshub/sicau/jk/<valid-gid>/<valid-type>","handlingStrategy":"try-catch","validationCode":"const res = await Promise.all([query(1), query(2)]);\nfor (const each of res) {\n    if (each.code !== '0') {\n        return ctx.body(`Upstream SICAU API error: ${each.message}`, 502);\n    }\n}","typeGuard":"const isUpstreamOk = (r: unknown): boolean => (r as any)?.code === '0';","tryCatchPattern":"try {\n    for (const each of res) apiSuccessAssert(each);\n} catch (e) {\n    if (e instanceof Error && /upstream/.test(e.message)) { /* degrade gracefully */ }\n    throw e;\n}","preventionTips":["Validate gid/typeId against gidDict/typeDict before issuing the query.","Add a retry with backoff for transient upstream failures.","Surface the upstream message verbatim to aid diagnosis."],"tags":["upstream-api","parameter-validation","university"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}