{"record":{"id":"4f6260505b331795","repo":"DIYgod/RSSHub","slug":"response-msg","errorCode":null,"errorMessage":"${response.msg}","messagePattern":"\\$\\{response\\.msg\\}","errorType":"exception","errorClass":"Error","httpStatus":503,"severity":"error","filePath":"lib/routes/followin/index.ts","lineNumber":80,"sourceCode":"\nasync function handler(ctx) {\n    const { categoryId = '1', lang = 'en' } = ctx.req.param();\n    const { limit = 20 } = ctx.req.query();\n    const gToken = await getGToken();\n    const bParam = getBParam(lang);\n\n    const { data: response } = await got.post(`${apiUrl}/feed/list/recommended`, {\n        headers: {\n            'x-bparam': JSON.stringify(bParam),\n            'x-gtoken': gToken,\n        },\n        json: {\n            category_id: Number.parseInt(categoryId),\n            count: Number.parseInt(limit),\n        },\n    });\n    if (response.code !== 2000) {\n        throw new Error(response.msg);\n    }\n\n    const buildId = await getBuildId();\n\n    const list = parseList(response.data.list, lang, buildId);\n    const items = await Promise.all(list.map((item) => parseItem(item)));\n\n    return {\n        title: 'Followin',\n        link: 'https://followin.io',\n        image: favicon,\n        item: items,\n    };\n}\n","sourceCodeStart":62,"sourceCodeEnd":95,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/followin/index.ts#L62-L95","documentation":"Thrown when the Followin (followin.io) recommended feed API at `${apiUrl}/feed/list/recommended` returns a response with `code !== 2000` (the success code). The route authenticates with a computed `x-bparam` (browser fingerprint) and `x-gtoken`, then posts with a category_id and count. Any non-2000 code causes the upstream `msg` field to be rethrown verbatim. This is a passthrough of API-level errors.","triggerScenarios":"An invalid or unsupported categoryId is passed (the API returns an error code). The x-gtoken or x-bparam computation is stale or rejected by Followin's anti-bot system. The API rate-limits the RSSHub instance. Followin changed their success code or API contract.","commonSituations":"User passes a categoryId not in the documented list (1, 3, 5, 6, 8, 9, 11, 13, 14). Followin updates their anti-bot token generation, invalidating getGToken/getBParam. Rate-limiting after frequent polling. The API endpoint path or version changed.","solutions":["Verify the categoryId is one of the documented values: 1, 3, 5, 6, 8, 9, 11, 13, or 14.","Check whether the getGToken and getBParam utilities in utils.ts still produce valid tokens by testing against the Followin API directly.","If the error is intermittent, reduce request frequency to avoid rate-limiting.","Log `response` to inspect the full error code and message for diagnosis."],"exampleFix":"// before\nif (response.code !== 2000) {\n    throw new Error(response.msg);\n}\n\n// after — include the code and categoryId for faster diagnosis\nif (response.code !== 2000) {\n    throw new Error(`Followin feed/list/recommended error (code=${response.code}, categoryId=${categoryId}): ${response.msg}`);\n}","handlingStrategy":"try-catch","validationCode":"const VALID_CATEGORY_IDS = new Set(['1', '3', '5', '6', '8', '9', '11', '13', '14']);\n\nfunction validateCategoryId(id: string | undefined): string {\n    const resolved = id ?? '1';\n    if (!VALID_CATEGORY_IDS.has(resolved)) {\n        throw new InvalidParameterError(`Invalid categoryId: ${id}. Valid: 1, 3, 5, 6, 8, 9, 11, 13, 14`);\n    }\n    return resolved;\n}","typeGuard":"interface FollowinSuccessResponse {\n    code: 2000;\n    data: { list: unknown[] };\n}\n\nfunction isFollowinSuccess(res: unknown): res is FollowinSuccessResponse {\n    return typeof res === 'object' && res !== null &&\n        (res as any).code === 2000;\n}","tryCatchPattern":"try {\n    const { data: response } = await got.post(url, options);\n    if (response.code !== 2000) {\n        throw new Error(`Followin API error (code=${response.code}): ${response.msg}`);\n    }\n} catch (e) {\n    if (e instanceof Error && e.message.includes('Followin API error')) {\n        // API-level rejection — likely token or categoryId issue\n    }\n    throw e;\n}","preventionTips":["Validate categoryId against the documented set before calling the API.","Keep getGToken and getBParam utilities updated when Followin changes their anti-bot mechanism.","Log the full response (code + msg) for diagnosis of token or rate-limit issues.","Cache the gToken and bParam to reduce token-generation overhead and avoid detection."],"tags":["api-passthrough","anti-bot","token-auth","followin"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}