{"record":{"id":"c2e008840637a88a","repo":"DIYgod/RSSHub","slug":"rss-c2e008","errorCode":null,"errorMessage":"该 RSS 源由于配置不正确而被禁用：令牌丢失。","messagePattern":"该 RSS 源由于配置不正确而被禁用：令牌丢失。","errorType":"exception","errorClass":"ConfigNotFoundError","httpStatus":null,"severity":"error","filePath":"lib/routes/zsxq/user.ts","lineNumber":41,"sourceCode":"    ],\n    features: {\n        requireConfig: [\n            {\n                name: 'ZSXQ_ACCESS_TOKEN',\n                description:\n                    '知识星球访问令牌,获取方式：\\n1. 登录知识星球网页版\\n2. 打开浏览器开发者工具，切换到 Application 面板\\n3. 点击侧边栏中的Storage -> Cookies -> https://wx.zsxq.com\\n4. 复制 Cookie 中的 zsxq_access_token 值',\n            },\n        ],\n    },\n    handler,\n};\n\nasync function handler(ctx: Context): Promise<Data> {\n    const uid = ctx.req.param('id');\n    const accessToken = config.zsxq.accessToken;\n\n    if (!accessToken) {\n        throw new ConfigNotFoundError('该 RSS 源由于配置不正确而被禁用：令牌丢失。');\n    }\n\n    let count = Number(ctx.req.query('limit')) || 20;\n    if (count > 30) {\n        count = 30;\n    }\n\n    const userInfo = await customFetch<UserInfoResponse>(`/users/${uid}`);\n\n    const { topics } = await customFetch<TopicsResponse>(`/users/${uid}/topics/footprint?count=${count}`);\n\n    return {\n        title: `知识星球 - ${userInfo.user.name}`,\n        description: userInfo.user.introduction,\n        image: userInfo.user.avatar_url,\n        link: `https://wx.zsxq.com/dweb2/index/footprint/${uid}`,\n        item: generateTopicDataItem(topics),\n    };","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/zsxq/user.ts#L23-L59","documentation":"Same ConfigNotFoundError pattern as the group route, but in lib/routes/zsxq/user.ts. The handler guards config.zsxq.accessToken before fetching /users/:id and throws when it is absent. RSSHub treats ConfigNotFoundError specially so the feed reports a configuration problem rather than an internal error.","triggerScenarios":"Requesting /zsxq/user/:id (user footprint/feed) while ZSXQ_ACCESS_TOKEN is unset or empty. The guard at user.ts:40 fires before the /users/${uid} call.","commonSituations":"Operator forgot to set the token for the user route even if other zsxq routes work; env var typo (e.g. ZSXQ_TOKEN instead of ZSXQ_ACCESS_TOKEN); token rotated and not updated.","solutions":["Set ZSXQ_ACCESS_TOKEN exactly (note the full name) from the wx.zsxq.com cookie.","Restart RSSHub after setting it.","Confirm both /zsxq/group and /zsxq/user read the same env var — fixing it fixes both.","If using a secrets manager, ensure the var is injected into the RSSHub process env."],"exampleFix":"// before: /zsxq/user/2414218251 -> 'route disabled'\n// after: export ZSXQ_ACCESS_TOKEN=<token-from-cookie> && restart","handlingStrategy":"validation","validationCode":"import { config } from '@/config';\nif (!config.zsxq?.accessToken) {\n  // do not expose /zsxq/user — warn operator at boot\n  console.warn('ZSXQ_ACCESS_TOKEN missing — /zsxq/user disabled.');\n}","typeGuard":"import ConfigNotFoundError from '@/errors/types/config-not-found';\nfunction isConfigNotFoundError(e: unknown): e is ConfigNotFoundError {\n  return e instanceof Error && (e as ConfigNotFoundError).name === 'ConfigNotFoundError';\n}","tryCatchPattern":"try {\n  await fetchZsxqUser(uid);\n} catch (e) {\n  if (isConfigNotFoundError(e)) return respondDisabled('Set ZSXQ_ACCESS_TOKEN');\n  throw e;\n}","preventionTips":["Use the exact env var name ZSXQ_ACCESS_TOKEN (common typo: ZSXQ_TOKEN).","Both /zsxq/group and /zsxq/user share one token — set it once.","Reload RSSHub after editing the env so the value is re-read."],"tags":["config","zsxq","authentication","environment","rsshub"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}