{"record":{"id":"d4a3c347365148c3","repo":"DIYgod/RSSHub","slug":"unsupported-key","errorCode":null,"errorMessage":"Unsupported key","messagePattern":"Unsupported key","errorType":"validation","errorClass":"InvalidParameterError","httpStatus":503,"severity":"warning","filePath":"lib/routes/nhentai/index.ts","lineNumber":38,"sourceCode":"        supportBT: true,\n        nsfw: true,\n    },\n    radar: [\n        {\n            source: ['nhentai.net/:key/:keyword'],\n            target: '/index/:key/:keyword',\n        },\n    ],\n    name: 'Filter',\n    maintainers: ['MegrezZhu', 'hoilc', 'pseudoyu'],\n    handler,\n};\n\nasync function handler(ctx) {\n    const { key, keyword, mode } = ctx.req.param();\n\n    if (!supportedKeys.has(key)) {\n        throw new InvalidParameterError('Unsupported key');\n    }\n\n    const url = `https://nhentai.net/${key}/${keyword.toLowerCase().replace(' ', '-')}/`;\n\n    const simples = await getSimple(url);\n\n    const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 5;\n    let items = simples;\n    if (mode === 'detail') {\n        items = await getDetails(cache, simples, limit);\n    } else if (mode === 'torrent') {\n        items = await getTorrents(cache, simples, limit);\n    }\n\n    return {\n        title: `nhentai - ${key} - ${keyword}`,\n        link: url,\n        description: 'hentai',","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/nhentai/index.ts#L20-L56","documentation":"An InvalidParameterError from the nhentai filter route. The route defines a whitelist Set of seven keys (parody, character, tag, artist, group, language, category) and rejects any other value before building the nhentai.net URL. It is a user-input validation guard, not an upstream failure.","triggerScenarios":"Calling /nhentai/index/:key/:keyword with a key not in supportedKeys — e.g. /nhentai/index/genre/xxx, /nhentai/index/search/xxx, typos like /nhentai/index/Language/xxx (case-sensitive), or copied URLs where the path segment does not correspond to a nhentai filter namespace.","commonSituations":"User mistypes the filter key; user assumes a key (like 'search' or 'genre') exists when it does not; case mismatch (the Set is lowercase); copy-pasting a nhentai URL segment that is not a real filter path.","solutions":["Use one of the documented keys: parody, character, tag, artist, group, language, or category.","Make sure the key is lowercase — the whitelist Set is case-sensitive.","Cross-check the value against the route's parameters docs in the route definition."],"exampleFix":"// before\nif (!supportedKeys.has(key)) {\n    throw new InvalidParameterError('Unsupported key');\n}\n\n// after — caller fix: use a valid key\n//   GET /nhentai/index/language/chinese   ✓\n//   GET /nhentai/index/tag/xxx            ✓","handlingStrategy":"validation","validationCode":"const SUPPORTED = new Set(['parody','character','tag','artist','group','language','category']);\nfunction buildNhentaiUrl(key, keyword) {\n  if (!SUPPORTED.has(key)) throw new Error(`Unsupported key '${key}'. Valid: ${[...SUPPORTED].join(', ')}`);\n  return `https://nhentai.net/${key}/${keyword.toLowerCase().replace(' ', '-')}/`;\n}","typeGuard":"const isSupportedKey = (k: string): k is 'parody'|'character'|'tag'|'artist'|'group'|'language'|'category' =>\n  SUPPORTED.has(k);","tryCatchPattern":null,"preventionTips":["Validate the key client-side before requesting the RSSHub route.","Keep keys lowercase — the whitelist is case-sensitive.","Surface the valid set in your client's error message."],"tags":["validation","route-parameter","user-input","nhentai"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}