{"record":{"id":"8e2c0a79b9102d18","repo":"DIYgod/RSSHub","slug":"invalid-locals-content-route-option-supported-fil","errorCode":null,"errorMessage":"Invalid Locals content route option. Supported filters are `plus` and `nonplus`, and supported content types are `video`, `live`, `audio`, `podcast`, `article`, `document`, and `pdf`.","messagePattern":"Invalid Locals content route option\\. Supported filters are `plus` and `nonplus`, and supported content types are `video`, `live`, `audio`, `podcast`, `article`, `document`, and `pdf`\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/routes/locals/feed.ts","lineNumber":341,"sourceCode":"        description: renderDescription(image, post.text),\n        image,\n        itunes_item_image: image,\n        link: post.share_url,\n        pubDate: post.published ? parseDate(post.published) : post.post_date ? parseDate(post.post_date) : undefined,\n        title: getTitle(post),\n    };\n}\n\nfunction parseOptions(option1: string | undefined, option2: string | undefined) {\n    const values = [option1, option2].filter(Boolean) as string[];\n    const hasFilter = (value: string): value is ContentFilter => Object.hasOwn(contentFilterMap, value);\n    const hasContentType = (value: string): value is ContentType => Object.hasOwn(contentTypeMap, value);\n    const filter = values.find((value) => hasFilter(value));\n    const contentType = values.find((value) => hasContentType(value));\n    const unknown = values.find((value) => !hasFilter(value) && !hasContentType(value));\n\n    if (unknown) {\n        throw new Error('Invalid Locals content route option. Supported filters are `plus` and `nonplus`, and supported content types are `video`, `live`, `audio`, `podcast`, `article`, `document`, and `pdf`.');\n    }\n\n    return {\n        contentType: contentType ? contentTypeMap[contentType] : undefined,\n        filter,\n    };\n}\n\nasync function requestServerFunction<T>(session: string, id: string, key: string, args: unknown[]) {\n    const response = await ofetch.raw(`${rootUrl}/_server`, {\n        body: createRequestBody(args),\n        headers: {\n            'Content-Type': 'application/json',\n            ...getRequestHeaders(session),\n            'X-Server-Id': id,\n            'X-Server-Instance': key,\n        },\n        method: 'POST',","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/locals/feed.ts#L323-L359","documentation":"Thrown by `parseOptions` (lib/routes/locals/feed.ts:341) when one of the two path options (`option1`/`option2`) is neither a recognized content filter (`plus`, `nonplus`) nor a recognized content type (`video`, `live`, `audio`, `podcast`, `article`, `document`, `pdf`, plus aliases `live_stream`/`podcasts`). This guards the route's optional path segments before any network call.","triggerScenarios":"Requesting `/locals/<community>/<bad>` or `/locals/<community>/<filter>/<badType>` with a typo or unsupported value — e.g. `/locals/foo/articles`, `/locals/foo/free`, `/locals/foo/images`.","commonSituations":"Users assuming plural/alternate names not in the alias map; passing a filter where a type is expected and vice versa; passing three segments.","solutions":["Use only documented values: filters `plus`/`nonplus`; types `video`, `live`, `audio`, `podcast`, `article`, `document`, `pdf`.","Drop the option entirely if you want the unfiltered feed.","If a new content type is needed, add it to `contentTypeMap` in lib/routes/locals/feed.ts:15."],"exampleFix":"// before: GET /locals/mycommunity/articles\n// after:  GET /locals/mycommunity/article","handlingStrategy":"validation","validationCode":"const FILTERS = ['plus', 'nonplus'];\nconst TYPES = ['video', 'live', 'audio', 'podcast', 'article', 'document', 'pdf', 'live_stream', 'podcasts'];\nfunction isValidLocalsOption(v: string): boolean {\n    return FILTERS.includes(v) || TYPES.includes(v);\n}\nfor (const opt of [option1, option2].filter(Boolean)) {\n    if (!isValidLocalsOption(opt)) throw new TypeError(`Unknown Locals option '${opt}'`);\n}","typeGuard":"function isContentFilter(v: string): v is 'plus' | 'nonplus' { return v === 'plus' || v === 'nonplus'; }\nfunction isContentType(v: string): boolean { return TYPES.includes(v); }","tryCatchPattern":"try {\n    parseOptions(option1, option2);\n} catch (e) {\n    if (e instanceof Error && /Invalid Locals content route option/.test(e.message)) {\n        return { error: 'Use a filter (plus|nonplus) or a content type (video|live|audio|podcast|article|document|pdf)' };\n    }\n    throw e;\n}","preventionTips":["Document the accepted values in the route `parameters`.","Normalize plurals/aliases centrally in the maps so callers don't guess.","Reject unknown options early instead of forwarding them."],"tags":["invalid-input","route-parameter","locals"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}