ErrLookup › Background articles › InvalidParameterError: RSSHub HTTP 400 "invalid parameter" errors — why route parameter validation fails and how to fix it

InvalidParameterError: RSSHub HTTP 400 "invalid parameter" errors — why route parameter validation fails and how to fix it

InvalidParameterError is the validation error thrown by route handlers when a path parameter fails its guard: an unknown category, subsite, or sort key; a non-hostname-safe value where a subdomain is expected; a malformed composite type string; or a resource that does not exist. It serializes to an HTTP 400 response, so the caller sees a client-error status rather than a crash or a 500. This article maps the whole family across the RSSHub codebase: the validation patterns behind it, the most frequent triggers, the known dead-guard bugs that mask it, and the fixes that hold across routes.

Distilled from 210 documented records across 2 repositories.

Background

InvalidParameterError is produced inside route handlers, before any upstream request is made. Guards fire immediately after the path parameters are extracted, so when the throw happens no network call to the target site has occurred; this distinguishes it from fetch failures, which surface as different error classes. To the caller it looks uniform: RSSHub serializes the error to an HTTP 400 with a localized "invalid parameter" body, and any HTML in the message (such as a docs link) is rendered as-is. Because the check is local, the error is almost always the client's mistake — the wrong value was passed — though a minority of routes use the same error class for existence checks against upstream APIs, which conflates "not found" with "invalid".

Four validation shapes recur across the family. First, membership checks against a fixed set: the handler tests the parameter with Object.hasOwn or Object.keys(...).includes against a config object, categories map, or sortMap, and throws when the key is absent. Second, hostname-shape validation: values that get interpolated into a URL subdomain (https://${language}.eagle.cool, https://${user}.substack.com) are run through a DNS-label regex that rejects dots, underscores, slashes, leading/trailing hyphens, and values over 63 characters. This check is purely structural — an unsupported but well-formed value like a wrong region code passes validation and produces an empty or broken feed instead of an error. Third, composite type strings: parameters like <period>_<genre>_<novelType> are split and each segment validated against its own enum, with some segments optional on one route and mandatory on a sibling route. Fourth, semantic lookups: some handlers call an upstream API (user slug resolution, novel search, channel listing) and throw this same error class when the response indicates the resource does not exist.

The family also documents real defects in the guards themselves. Two routes validate numeric parameters with Number.isNaN(x) where x is always a string, so the check never fires and invalid input flows downstream to fail in confusing ways; one route tests the truthiness of a filter result that is always an array, making the error dead code that yields an empty feed instead. Conversely, some defensive arms are deliberately unreachable in the normal call path — they exist only to catch enum/lookup-map drift introduced by maintainers. Message quality varies: some errors embed the valid values or a docs link, one echoes the wrong path segment, and several are localized in Chinese with exact string matching against Chinese province names or page headings. Where two routes share a similarly named enum, the member sets can differ (a subsite code valid on the ranking route throws on the search route; a ranking period valid in the general list is excluded from the R18 list), so the same value can be valid or invalid depending on the route — the behavior is route-specific, and the records disagree rather than follow one rule.

Common causes

What usually fixes it

Go deeper

Documented occurrences

…and 190 more across the corpus — use search.

Honest provenance: generated on 2026-08-15 from AI-assisted analysis of the linked records. See how records are made.