From 6fb2ea338bf597d27ff60d8b11fa251e0f149614 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 12 Aug 2026 17:51:32 +0000 Subject: [PATCH] docs(api): document the repeated-filter refusal on GET /data/:object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `content/docs/api/data-api.mdx` documents the `filter` parameter's rejection behaviour, but named only malformed JSON as a cause of `400 INVALID_FILTER`. PR #8004 (#7390) shipped a second cause on the same slot: sending one spelling more than once. The page was incomplete, not wrong — the malformed-JSON sentence stays as it was. - the `filter` table row now names repetition alongside malformed JSON - the "a filter either applies or fails" table gains the repetition row, quoting the shipped message from `repeatedFilterParamMessage()` - one paragraph carries the shipped reasoning: a repeat is neither merged nor resolved by precedence, and repetition is counted rather than compared, so a one-element array from a repeat-preserving adapter is still one occurrence Docs-only; no published package changes. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01BgZEGQqkLtHZBKrP2ceDwA --- content/docs/api/data-api.mdx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/content/docs/api/data-api.mdx b/content/docs/api/data-api.mdx index 2d83970fe5..988057c1a0 100644 --- a/content/docs/api/data-api.mdx +++ b/content/docs/api/data-api.mdx @@ -19,7 +19,7 @@ Query records with filtering, sorting, selection, and pagination. |:----------|:---------|:------------| | `object` | path | Object name | | `select` | query | Comma-separated field names. Every name must exist — an unknown one is `400 INVALID_FIELD`, never dropped. | -| `filter` | query | Filter expression (JSON). `filters` also accepted for backward compatibility. Malformed JSON is rejected with `400 INVALID_FILTER` — never ignored. | +| `filter` | query | Filter expression (JSON). `filters` also accepted for backward compatibility. Malformed JSON is rejected with `400 INVALID_FILTER` — never ignored; so is sending the parameter more than once (`?filter=…&filter=…`), which is refused as a repetition rather than diagnosed as malformed. | | `sort` | query | Sort expression (e.g. `name asc` or `-created_at`). Must name a real field on the object itself — an unknown name or a dotted path (`account.company_name`) is `400 INVALID_SORT`. | | `top` | query | Max records to return. No default — omitting it returns all matching records. | | `skip` | query | Offset | @@ -76,9 +76,18 @@ successful query: | `?filter=5`, `?filter="done"`, `?filter=null` | `400` — parses, but is not a filter | | `?filter=` (blank) | treated as absent — no filter, no error | | `where` and `filter` sent with **different** values | `400` — aliases for one slot; send exactly one | +| `?filter={"a":1}&filter={"b":2}` — one spelling sent **twice** | `400` — `Repeated "filter" query parameter — send exactly one` | The same rule applies to `orderby` on `GET /data/:object/export`. +Sending one spelling **twice** — on `GET /data/:object`, in any of the four +spellings — is refused as its own named cause rather than reported as a +malformed filter: a repeat is neither merged nor resolved by precedence, +because either would apply a filter you did not express. Repetition is counted, +not compared, so two identical occurrences are still two occurrences, while a +single occurrence that a server adapter delivers as a one-element array is +still one. + #### Nor is a sort, a projection, or an expansion `filter` is not the only parameter that names a field. `sort`, `select` and