{"record":{"id":"99a048079da0e997","repo":"DIYgod/RSSHub","slug":"id-https-www-jisilu-cn-explore","errorCode":null,"errorMessage":"请填入合法的分类 id，参见广场 https://www.jisilu.cn/explore/","messagePattern":"请填入合法的分类 id，参见广场 https://www\\.jisilu\\.cn/explore/","errorType":"validation","errorClass":"InvalidParameterError","httpStatus":null,"severity":"warning","filePath":"lib/routes/jisilu/category.ts","lineNumber":16,"sourceCode":"import type { CheerioAPI } from 'cheerio';\nimport { load } from 'cheerio';\nimport type { Context } from 'hono';\n\nimport InvalidParameterError from '@/errors/types/invalid-parameter';\nimport type { Data, DataItem, Language, Route } from '@/types';\nimport { ViewType } from '@/types';\nimport ofetch from '@/utils/ofetch';\n\nimport { processItems, rootUrl } from './util';\n\nexport const handler = async (ctx: Context): Promise<Data> => {\n    const { id } = ctx.req.param();\n\n    if (!id) {\n        throw new InvalidParameterError('请填入合法的分类 id，参见广场 https://www.jisilu.cn/explore/');\n    }\n\n    const limit = Number(ctx.req.query('limit') ?? '30');\n\n    const targetUrl: string = new URL(`/category/${id}`, rootUrl).href;\n\n    const response = await ofetch(targetUrl);\n    const $: CheerioAPI = load(response);\n    const language: string = $('html').prop('lang') ?? 'zh';\n\n    const items: DataItem[] = await processItems($, $('div.aw-question-list'), limit);\n\n    $('div.pagination').remove();\n\n    const author = $('meta[name=\"keywords\"]').prop('content').split(/,/, 1)[0];\n    const feedImage = $('div.aw-logo img').prop('src');\n\n    return {","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/jisilu/category.ts#L1-L34","documentation":"Thrown by the jisilu (集思录) category handler as InvalidParameterError when the `id` path parameter is falsy (empty string, undefined). The handler builds `/category/${id}` against rootUrl, so an empty id would produce a malformed URL; the guard rejects it before the request is made.","triggerScenarios":"Request to /jisilu/category/ with no id segment, or an id that evaluates to empty string (e.g. a lone slash or whitespace). Note: only a truly empty id is rejected — a non-existent but non-empty category id passes this check and fails later during parsing.","commonSituations":"Misrouted request missing the id; user constructs the URL by hand and omits the category; reverse-proxy rewrite strips the segment.","solutions":["Provide a valid category slug from https://www.jisilu.cn/explore/ — e.g. /jisilu/category/fund","Confirm the route path /jisilu/category/:id is fully populated","If a non-empty-but-wrong id slips through, add a post-fetch empty-result check as a second guard"],"exampleFix":"// before\nif (!id) {\n    throw new InvalidParameterError('请填入合法的分类 id，参见广场 https://www.jisilu.cn/explore/');\n}\n// after — also validate against a known set if maintained\nconst KNOWN = new Set(['fund', 'stock', 'bond', 'lof', ...]);\nif (!id || !KNOWN.has(id)) {\n    throw new InvalidParameterError(`请填入合法的分类 id，参见广场 https://www.jisilu.cn/explore/ (got '${id ?? ''}')`);\n}","handlingStrategy":"validation","validationCode":"function hasCategoryId(id: string | undefined): id is string {\n  return typeof id === 'string' && id.trim().length > 0;\n}\nif (!hasCategoryId(ctx.req.param('id'))) {\n  return ctx.json({ error: 'category id required' }, 400);\n}","typeGuard":"function isNonEmptyString(v: unknown): v is string {\n  return typeof v === 'string' && v.trim().length > 0;\n}","tryCatchPattern":"try {\n  return await handler(ctx);\n} catch (e) {\n  if (e instanceof InvalidParameterError && /分类 id/.test(e.message)) {\n    return ctx.json({ error: e.message }, 400);\n  }\n  throw e;\n}","preventionTips":["Make path params required (non-optional) in the route definition where possible","Trim input before validation","Add a secondary post-fetch empty-result guard for non-empty-but-wrong ids","Link users to the explore page in the error message"],"tags":["validation","parameter"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}