{"record":{"id":"fe9de20f4fc92e30","repo":"DIYgod/RSSHub","slug":"invalid-type-type-supported-types-object-k","errorCode":null,"errorMessage":"Invalid type: ${type}. Supported types: ${Object.keys(typeMap).join(', ')}","messagePattern":"Invalid type: (.+?)\\. Supported types: (.+?)","errorType":"validation","errorClass":"InvalidParameterError","httpStatus":503,"severity":"error","filePath":"lib/routes/xueqiu/stock-info.ts","lineNumber":53,"sourceCode":"};\n\n// The two endpoints below correspond to the tabs on the stock page (xueqiu.com/S/:id).\n// `source` is the API query value; `label` is the human-readable name shown in the feed title.\n// `all` / `discuss` / `trans` are served by the search endpoint; `news` / `announcement`\n// are served by the timeline endpoint (the search endpoint ignores these two sources).\nconst typeMap = {\n    all: { source: 'all', label: '全部', endpoint: 'search' },\n    discuss: { source: 'user', label: '讨论', endpoint: 'search' },\n    trans: { source: 'trans', label: '交易', endpoint: 'search' },\n    news: { source: '自选股新闻', label: '资讯', endpoint: 'timeline' },\n    announcement: { source: '公告', label: '公告', endpoint: 'timeline' },\n};\n\nasync function handler(ctx) {\n    const id = ctx.req.param('id');\n    const type = ctx.req.param('type') || 'announcement';\n    if (!Object.hasOwn(typeMap, type)) {\n        throw new InvalidParameterError(`Invalid type: ${type}. Supported types: ${Object.keys(typeMap).join(', ')}`);\n    }\n    const { source, label, endpoint } = typeMap[type];\n\n    const link = `https://xueqiu.com/S/${id}`;\n    const cookie = await parseToken(link);\n\n    // Fetch the stock name from the lightweight quote API (the name is rendered\n    // client-side on the page, so it cannot be scraped from the static HTML)\n    const quoteRes = await got({\n        method: 'get',\n        url: 'https://stock.xueqiu.com/v5/stock/quote.json',\n        searchParams: queryString.stringify({ symbol: id }),\n        headers: {\n            Cookie: cookie,\n            Referer: link,\n        },\n    });\n    const stock_name = quoteRes.data.data?.quote?.name || id;","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/xueqiu/stock-info.ts#L35-L71","documentation":"InvalidParameterError thrown by the Xueqiu stock-info handler when ctx.req.param('type') is not a key of typeMap (all, discuss, trans, news, announcement). The type selects both the search source label and which endpoint (search vs timeline) to call, so an unknown type cannot be defaulted safely.","triggerScenarios":"A request to /xueqiu/stock-info/:id/:type where type is outside the five keys, e.g. /xueqiu/stock-info/SH600519/comment or omitting it in a path that still passes a third segment. Validated before any Xueqiu call.","commonSituations":"Caller used a type name from another Xueqiu route; typo; integrator expected 'comments' instead of 'discuss'.","solutions":["Use one of: all, discuss, trans, news, announcement.","If you want the default, omit the type segment (the handler defaults to 'announcement').","Add new types to typeMap if Xueqiu exposes a new feed."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const TYPE_KEYS = new Set(Object.keys(typeMap));\nfunction resolveType(raw: string | undefined) {\n    const type = raw || 'announcement';\n    if (!TYPE_KEYS.has(type)) {\n        throw new InvalidParameterError(`Invalid type \"${type}\". Supported: ${[...TYPE_KEYS].join(', ')}`);\n    }\n    return type as keyof typeof typeMap;\n}","typeGuard":"function isStockInfoType(value: string): value is keyof typeof typeMap {\n    return Object.hasOwn(typeMap, value);\n}","tryCatchPattern":null,"preventionTips":["Derive the allow-list from typeMap keys so docs and validation stay in sync.","Default to 'announcement' when omitted (matches existing behavior).","Add new types to typeMap if Xueqiu introduces new feeds."],"tags":["xueqiu","validation","route-param"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}