{"record":{"id":"dcacfa9990e5838c","repo":"DIYgod/RSSHub","slug":"invalid-channel-name","errorCode":null,"errorMessage":"Invalid channel name","messagePattern":"Invalid channel name","errorType":"validation","errorClass":"InvalidParameterError","httpStatus":503,"severity":"error","filePath":"lib/routes/21caijing/channel.ts","lineNumber":57,"sourceCode":"    }\n\n    return result;\n};\n\nexport const handler = async (ctx: Context): Promise<Data> => {\n    const { name = '热点' } = ctx.req.param();\n    const limit = Number(ctx.req.query('limit') ?? '30');\n\n    const domain = 'm.21jingji.com';\n    const baseUrl = `https://${domain}`;\n    const staticBaseUrl = 'https://static.21jingji.com';\n    const menuUrl: string = new URL('m/webMenu.json', staticBaseUrl).href;\n\n    const menuResponse = await ofetch(menuUrl);\n    const menu = processMenu(menuResponse);\n\n    if (!menu.hasOwnProperty(name)) {\n        throw new InvalidParameterError('Invalid channel name');\n    }\n\n    const currentChannel = menu[name];\n\n    const apiUrl: string = new URL(currentChannel.apiUrl, baseUrl).href;\n    const targetUrl: string = new URL(`#/${currentChannel.url}`, baseUrl).href;\n    const authUrl: string = new URL('reader/cbhChannelAuth', baseUrl).href;\n\n    const targetResponse = await ofetch(targetUrl);\n    const $: CheerioAPI = load(targetResponse);\n    const language: string = $('html').attr('lang') ?? 'zh-CN';\n\n    const authResponse = await ofetch(authUrl, {\n        method: 'POST',\n        responseType: 'json',\n    });\n\n    const response = await ofetch(apiUrl, {","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/21caijing/channel.ts#L39-L75","documentation":"The 21财经 channel route fetches a remote webMenu.json from static.21jingji.com and verifies the requested channel `name` is a key in that live menu before composing the API URL. InvalidParameterError is thrown if the channel is not present, because the subsequent API call would be meaningless.","triggerScenarios":"Calling /21caijing/channel/:name with a value that is not a property of the fetched m/webMenu.json — a typo, a renamed channel, or a channel the app retired.","commonSituations":"The menu changed upstream (channel renamed/removed); copy-pasting a stale name; the default '热点' no longer being present after a redesign.","solutions":["Open https://static.21jingji.com/m/webMenu.json and copy an existing key verbatim.","Fall back to the default by omitting the segment (defaults to '热点').","If the menu endpoint itself moved, report it to maintainers — the URL may need updating."],"exampleFix":"// before\n/21caijing/channel/hotnews        // not a key in webMenu.json\n// after\n/21caijing/channel/热点             // or omit the segment","handlingStrategy":"try-catch","validationCode":"// Cannot be fully pre-validated without fetching webMenu.json,\n// but you can pre-flight it:\nasync function channelExists(name) {\n  const menu = await ofetch('https://static.21jingji.com/m/webMenu.json');\n  return Object.prototype.hasOwnProperty.call(processMenu(menu), name);\n}","typeGuard":"function isInMenu(menu, name): name is string {\n  return typeof name === 'string' && Object.prototype.hasOwnProperty.call(menu, name);\n}","tryCatchPattern":"try {\n  return await build21caijingFeed(name);\n} catch (e) {\n  if (e instanceof InvalidParameterError && /Invalid channel name/.test(e.message)) {\n    // refresh the menu once and retry, else fall back to default '热点'\n    return await build21caijingFeed('热点');\n  }\n  throw e;\n}","preventionTips":["Cache webMenu.json with a short TTL so stale channel names surface quickly.","Default to '热点' when user input is unverified.","Watch for InvalidParameterError specifically and degrade rather than fail the whole feed."],"tags":["validation","upstream-dependent","parameter","rsshub"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}