ErrLookup › Background articles › "Invalid query parameter" / "Failed to parse value of ...": fixing bad query string parameters across APIs
"Invalid query parameter" / "Failed to parse value of ...": fixing bad query string parameters across APIs
"Invalid query parameter" errors appear when an HTTP API query string value fails validation or parsing — things like "Order "asc " parameter is wrong, allowed: asc or desc", "The "updatedSince" query parameter must be a valid date.", "Failed to parse value of "diff_version" (...) as a uint64", or "invalid MinimumShouldMatch value". Developers hit these when a query parameter is misspelled, wrongly typed, badly formatted, or not one of the whitelisted values the server accepts, and the request is rejected before any real work happens.
Distilled from 98 documented records across 36 repositories.
Background
These errors come from the input-validation layer of an HTTP server or API client, at the very start of request handling. Before a handler touches storage or runs business logic, it parses the query string and checks each parameter's shape: is this a date, a boolean, an unsigned integer, a UUID, or one of a fixed set of enum values? When the check fails, the request is rejected with a 400-class response (or, in looser libraries, an exception that surfaces as a 500). The message usually echoes the offending parameter name and raw value — Nomad's "Failed to parse value of %q (%v) as a bool" names the field and the string received, Jaeger's "unable to parse param '%s': %w" wraps the lower-level parser's cause, and rqlite returns the parse error text verbatim as the 400 body. The reason this validation exists at all is safety: wallabag interpolates the order value directly into a Doctrine ORDER BY clause, KubeSphere parses filter keys that could carry injection-prone characters, and PentAGI refuses group fields that are not whitelisted in its SQL mapper. Whitelisting also guarantees the query is semantically meaningful — Jaeger rejects an inverted start-time range because the resulting filter can never match, and Shardeum rejects a non-positive limit because LIMIT ? with zero or negative values is meaningless.
What this looks like from the caller's side is an immediate failure with no partial work: Nomad's tty check rejects the exec request before an allocation is targeted, Weaviate's tenant-activity filter check returns 400 before the activity call runs, and LiteLLM validates sort_order before any Prisma query executes. The response is often more diagnostic than the message suggests — reading the wrapped cause, the echoed raw value, or the 400 body usually tells you exactly which parameter and which string arrived. Common silent culprits on the client side are unexpanded shell variables, values mangled by URL encoding (a trailing %0A newline, double-encoded quotes), locale-formatted dates instead of ISO 8601, and UI labels like "ascending" passed through instead of the API's "asc".
The family varies noticeably across libraries in three ways. First, strictness differs: wallabag's order and detail parameters accept case-insensitive values but its expect parameter is case-sensitive and its tag-feed sort lookup is case-sensitive with no trimming; LiteLLM lowercases sort_order before checking, while Nomad accepts the full set of Go strconv.ParseBool literals (1/t/T/TRUE/true/True and counterparts) but nothing else. Second, the HTTP surface differs: most return a clean 400, but wallabag's findEntries throws a plain \Exception that surfaces as a 500, Bagisto's reporting controllers abort with a bare Laravel 404 "Not Found", and sure's UUID filter errors render as 422 validation_failed. Third, the semantics of "missing" differ: Rocket.Chat's emoji-custom.list treats an empty updatedSince as absent, but its sync endpoints fail on a missing updatedSince because Date.parse(undefined) is NaN — the parameter is effectively required; Nomad treats absent boolean and uint64 parameters as nil and skips them entirely. Some validators check format only (sure's UUID checks reject malformed ids but accept well-formed UUIDs for nonexistent records, returning an empty list), while others check membership in a documented value set.
Common causes
- Value not in the accepted enum or whitelist. Passing a direction, sort key, filter alias, strategy, or op that is not one of the documented values — sort_order=ascending instead of asc (LiteLLM), ?type=total-sales on the customer report (Bagisto), filter=xyz instead of reads/writes/all (Weaviate), type=map instead of m (Hadoop). Fix by using a documented value verbatim or omitting the parameter to get its default.
- Wrong type or format for the parameter. Dates not in ISO 8601 (updatedSince=yesterday or 31/12/2024 in Rocket.Chat), booleans spelled yes/on/1.0 where strconv.ParseBool is used (Nomad), diff_version=latest or -1 where a uint64 is expected, rule_id=abc where a UUID is required (sure), or a minimum_should_match expression like 2<75% the parser does not implement (ZincSearch).
- Encoding and shell artifacts corrupting the value. Unexpanded shell variables, double-encoded quotes (%272024-01-01%27), trailing whitespace or newlines (sort_order=desc%0A), array values (?order[]=asc breaks wallabag), or unquoted -q expressions split by the shell (Spree). The value that reaches the server is not the one you thought you sent.
- Empty or missing parameter handled inconsistently. Some endpoints treat empty as absent (Rocket.Chat's emoji-custom.list, Nomad's optional booleans), while others fail: an explicitly empty ?order= fails wallabag's in_array check, ?sort= with a blank value fails the feed's isset lookup, and Rocket.Chat sync endpoints reject a missing updatedSince entirely.
- Mixing up sibling parameters or reusing values across APIs. Copying sort into order on wallabag, sending -created with a direction prefix from another API's convention, using GET's detail values on DELETE's expect parameter, or passing a sales report slug to the customer report endpoint. Related parameters with similar names often have different accepted sets and case rules.
- Semantically impossible values. Some validators reject values that parse fine but make the query meaningless: Jaeger rejects StartTimeMin after StartTimeMax and DurationMin above DurationMax, and Shardeum rejects limit=0 or negative limits because the SQL LIMIT clause would return nothing.
- Casing and whitespace mismatches. Validation is often case-sensitive or whitespace-intolerant, and the rules vary even within one library: wallabag lowercases order/detail but not expect, its tag-feed sort lookup is case-sensitive, and Weaviate matches filter aliases case-insensitively but rejects extra whitespace. 'ASC', 'ID', or 'Created ' can fail where 'asc', 'id', or 'created' pass.
What usually fixes it
- Send values from the documented set exactly, or omit the parameter to take its default — most handlers skip absent parameters, and defaults exist for order, detail, expect, sort, filter, and diff_version across these records.
- Serialize values with the right type at the client boundary: toISOString() for dates, strconv.FormatBool or a native bool for booleans, plain base-10 integers for numeric params, canonical UUIDs taken from the corresponding list endpoints.
- Validate and normalize query parameters before the request leaves your code — whitelist enums, lowercase/trim where the server tolerates it (but verify case rules per endpoint), and clamp or swap paired bounds like min/max so ranges are never inverted and limits are at least 1.
- Build query strings with a typed client or shared URL-builder helper instead of string concatenation, URL-encode every value, and quote shell expressions so nothing is split or left unexpanded.
- Read the error diagnostic before retrying: the echoed parameter name and raw value, the wrapped cause, or the 400 body name the exact offending string — most of these failures are single-parameter typos, not server faults.
- Treat parameter names and accepted values as API contract: when a server-side slug or key is renamed, update every client that builds those URLs, and prefer a 400 with allowed values over generic 404/500 surfaces in your own wrappers.
Go deeper
- HTTP status errors: handling 4xx and 5xx responses — how to handle 4xx and 5xx responses properly.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Documented occurrences
- Order "{order}" parameter is wrong, allowed: asc or desc (wallabag/wallabag)
- error-roomId-param-invalid: The "${paramName}" query parameter must be a valid date. (RocketChat/Rocket.Chat)
- Failed to parse "{str}" to Boolean. (apache/hadoop)
- unknown strategy (badges/shields)
- Not Found (bagisto/bagisto)
- error-updatedSince-param-invalid: The "updatedSince" query parameter must be a valid date. (RocketChat/Rocket.Chat)
- Detail "{detail}" parameter is wrong, allowed: full or metadata (wallabag/wallabag)
- start Time Minimum is above Maximum (jaegertracing/jaeger)
- Failed to parse value of %q (%v) as a bool: %v (hashicorp/nomad)
- Sort "%s" is not available. (wallabag/wallabag)
- unable to parse param '%s': %w (jaegertracing/jaeger)
- invalid MinimumShouldMatch value (zincsearch/zincsearch)
- Invalid sort order. Must be 'asc' or 'desc' (BerriAI/litellm)
- Not Found (bagisto/bagisto)
- Invalid -q expression "${expression}" — expected key=value (e.g. -q status_eq=active) (spree/spree)
- validation_failed: rule_id must be a valid UUID (we-promise/sure)
- expect: 'id' or 'entry' expected, %s given (wallabag/wallabag)
- ErrToolcallsInvalidRequest: group field not found (vxcontrol/pentagi)
- Not Found (bagisto/bagisto)
- invalid conditions (kubesphere/kubesphere)
…and 78 more across the corpus — use search.
Honest provenance: generated on 2026-09-04 from AI-assisted analysis of the linked records. See how records are made.