{"record":{"id":"dc6b5f4c5312b121","repo":"DIYgod/RSSHub","slug":"invalid-category-valid-options-are-object-keys","errorCode":null,"errorMessage":"Invalid category. Valid options are: ${Object.keys(categories).filter(Boolean).join(', ')}","messagePattern":"Invalid category\\. Valid options are: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"lib/routes/hupu/index.ts","lineNumber":58,"sourceCode":"                label: value.title,\n                value: key,\n            })),\n        },\n    },\n    description: `::: tip\n电竞分类参见 [游戏热帖](https://bbs.hupu.com/all-gg) 的对应路由 [\\`/hupu/all/all-gg\\`](https://rsshub.app/hupu/all/all-gg)。\n:::`,\n    categories: ['bbs'],\n    radar: [\n        {\n            source: ['m.hupu.com/:category', 'm.hupu.com/'],\n            target: '/:category',\n        },\n    ],\n    handler: async (ctx): Promise<Data> => {\n        const c = ctx.req.param('category') || '';\n        if (!Object.hasOwn(categories, c)) {\n            throw new Error('Invalid category. Valid options are: ' + Object.keys(categories).filter(Boolean).join(', '));\n        }\n        const category = c as keyof typeof categories;\n\n        const rootUrl = 'https://m.hupu.com';\n        const currentUrl = `${rootUrl}/${category}`;\n\n        const response = await got({\n            method: 'get',\n            url: currentUrl,\n        });\n\n        const data = extractNextData<HupuApiResponse>(response.data, currentUrl);\n        const { pageProps } = data.props;\n\n        const dataKey = categories[category].data;\n        if (!Object.hasOwn(pageProps, dataKey)) {\n            throw new Error(`Expected '${dataKey}' property not found in pageProps for category: ${category || 'home'}`);\n        }","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/hupu/index.ts#L40-L76","documentation":"Thrown by the Hupu (虎扑) mobile site route when the `:category` path parameter is not a key in the `categories` object (which defines `nba`, `cba`, `soccer`, and `''` for home). The handler uses `Object.hasOwn(categories, c)` and throws a plain `Error` (not `InvalidParameterError`) listing valid options. Note that the empty string key `''` is valid (represents the home page), so omitting the category or passing `/` is accepted.","triggerScenarios":"Requesting `/hupu/<category>` where `<category>` is not `nba`, `cba`, `soccer`, or empty. Examples: `/hupu/nhl`, `/hupu/football`, `/hupu/esports`.","commonSituations":"User expects esports categories (the description redirects those to `/hupu/all/all-gg`), tries a sport not covered, or uses an old category slug. The `categories.options` in route config lists valid values.","solutions":["Use `nba`, `cba`, `soccer`, or omit the category for the home feed.","For esports content, use the separate `/hupu/all/all-gg` route as noted in the description.","As a maintainer: switch to `InvalidParameterError` for HTTP 400 semantics."],"exampleFix":"// before (broken)\n// GET /hupu/football\n\n// after (correct)\n// GET /hupu/soccer","handlingStrategy":"validation","validationCode":"const VALID_CATEGORIES = ['nba', 'cba', 'soccer', ''];\nfunction isValidCategory(c: string): boolean {\n    return VALID_CATEGORIES.includes(c);\n}","typeGuard":"function isKnownHupuCategory(c: string): c is 'nba' | 'cba' | 'soccer' | '' {\n    return c in categories;\n}","tryCatchPattern":null,"preventionTips":["Use `InvalidParameterError` instead of plain `Error` for HTTP 400 consistency.","Note that empty string is valid (home page) — omit the category parameter for the home feed.","Redirect esports users to `/hupu/all/all-gg` as documented."],"tags":["parameter-validation","rsshub","bbs"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}