What happened
sentry api lets you pass multiple -F key=value flags to select several columns, tags, or fields on a GET request. In practice only the last one survives — every earlier -F with the same key is silently overwritten, with no error or warning. The request goes out with far fewer parameters than the command line implies, and the resulting failure looks completely unrelated to a dropped CLI flag.
This is confusing for a human or an agent following the CLI's own -F key[]=value "array append" help text, because that syntax is real for POST/PUT JSON bodies but does nothing useful for GET query strings — it gets passed through literally as a query key named field[].
Why this is confusing in practice
Two real examples where this cost debugging time:
- Selecting multiple log columns with
-F 'field[]=timestamp' -F 'field[]=message' -F 'field[]=tags[shard_id,number]' against the logs dataset returned 500 Internal error. Please try again. It looked like the dataset didn't support multi-column or custom-tag selection at all. In reality only the last field was ever sent (the dry-run URL showed a single field%5B%5D=...), so Snuba rejected the under-specified request several layers downstream. Only inspecting --dry-run output revealed the missing fields.
- Combining
-F 'field=timestamp' -F 'sort=-timestamp' returned "orderby must also be in the selected columns or groupby" even though timestamp was clearly on the command line. The apparent bug looked like broken sort validation — but an earlier repeated -F field=... key had already silently overwritten itself, so the actual selected-columns list sent to the server didn't match what the command line implied.
In both cases the failure surfaces as an opaque server-side error several layers away from the real cause (a CLI flag silently dropped on the client), so the natural next debugging step — "this dataset/parameter must be unsupported" — is wrong and wastes time. Switching from -F to -f (raw field, no JSON parsing) fixed both cases, since -f already merges repeats into an array.
Root cause
Root cause is in packages/cli/src/commands/api.ts:
buildQueryParams() (used for -F key=value on GET requests) never merges repeated identical keys into an array — each call just does result[key] = value, so only the last -F field=x survives. This differs from buildRawQueryParams() (-f), which already merges repeats into string[].
- Bracket-array syntax (
key[]=value, documented in the -F help text as "Array append: {key: [value]}") is only implemented for the JSON-body path (parseFields/setNestedValue, used for POST/PUT). For GET requests, key[] is passed through literally as the string "field[]" with no stripping or special handling.
- The only tested way to send a multi-value GET param today is a single
-F 'field=["a","b"]' JSON-array value (see packages/cli/test/commands/api.test.ts).
Net effect: sentry api ORG/PROJECT/events/ -F field[]=timestamp -F field[]=message (or repeating -F field=x without brackets) silently sends a single query param literally named field[] with only the last value — not field=timestamp&field=message. Downstream, Sentry's Django request.GET.getlist("field") never matches field[], so the request resolves to zero selected columns. Against the ourlogs/logs dataset this surfaced as an opaque 500 Internal error. Please try again. (tracked separately in getsentry/sentry as SnubaRPCError: code: 400 — At least one column must be specified in the request, sentry.sentry.io issue 6683878692).
The -F help text presents key[]=value as a uniform rule for all requests, with no callout that it only applies to JSON request bodies, not GET query strings.
Proposed fixes
- Make
buildQueryParams() merge repeated identical -F field=x values into a real array/repeated query param, matching buildRawQueryParams()'s existing behavior.
- Either support
key[]=value bracket syntax for GET query building (stripping the brackets and merging into a repeat), or make it a validation error with a clear message instead of silently producing a mismatched literal field[] param.
- Update the
-F/--field help text to clarify that key[]=value array-append semantics are body-only; document the correct GET multi-value syntax (repeat -F field=x, or a JSON-array value).
via lorenzo.
--
View Junior Session [Sentry]
What happened
sentry apilets you pass multiple-F key=valueflags to select several columns, tags, or fields on a GET request. In practice only the last one survives — every earlier-Fwith the same key is silently overwritten, with no error or warning. The request goes out with far fewer parameters than the command line implies, and the resulting failure looks completely unrelated to a dropped CLI flag.This is confusing for a human or an agent following the CLI's own
-F key[]=value"array append" help text, because that syntax is real for POST/PUT JSON bodies but does nothing useful for GET query strings — it gets passed through literally as a query key namedfield[].Why this is confusing in practice
Two real examples where this cost debugging time:
-F 'field[]=timestamp' -F 'field[]=message' -F 'field[]=tags[shard_id,number]'against thelogsdataset returned500 Internal error. Please try again.It looked like the dataset didn't support multi-column or custom-tag selection at all. In reality only the last field was ever sent (the dry-run URL showed a singlefield%5B%5D=...), so Snuba rejected the under-specified request several layers downstream. Only inspecting--dry-runoutput revealed the missing fields.-F 'field=timestamp' -F 'sort=-timestamp'returned"orderby must also be in the selected columns or groupby"even thoughtimestampwas clearly on the command line. The apparent bug looked like broken sort validation — but an earlier repeated-F field=...key had already silently overwritten itself, so the actual selected-columns list sent to the server didn't match what the command line implied.In both cases the failure surfaces as an opaque server-side error several layers away from the real cause (a CLI flag silently dropped on the client), so the natural next debugging step — "this dataset/parameter must be unsupported" — is wrong and wastes time. Switching from
-Fto-f(raw field, no JSON parsing) fixed both cases, since-falready merges repeats into an array.Root cause
Root cause is in
packages/cli/src/commands/api.ts:buildQueryParams()(used for-F key=valueon GET requests) never merges repeated identical keys into an array — each call just doesresult[key] = value, so only the last-F field=xsurvives. This differs frombuildRawQueryParams()(-f), which already merges repeats intostring[].key[]=value, documented in the-Fhelp text as"Array append: {key: [value]}") is only implemented for the JSON-body path (parseFields/setNestedValue, used for POST/PUT). For GET requests,key[]is passed through literally as the string"field[]"with no stripping or special handling.-F 'field=["a","b"]'JSON-array value (seepackages/cli/test/commands/api.test.ts).Net effect:
sentry api ORG/PROJECT/events/ -F field[]=timestamp -F field[]=message(or repeating-F field=xwithout brackets) silently sends a single query param literally namedfield[]with only the last value — notfield=timestamp&field=message. Downstream, Sentry's Djangorequest.GET.getlist("field")never matchesfield[], so the request resolves to zero selected columns. Against theourlogs/logsdataset this surfaced as an opaque500 Internal error. Please try again.(tracked separately in getsentry/sentry asSnubaRPCError: code: 400 — At least one column must be specified in the request, sentry.sentry.io issue 6683878692).The
-Fhelp text presentskey[]=valueas a uniform rule for all requests, with no callout that it only applies to JSON request bodies, not GET query strings.Proposed fixes
buildQueryParams()merge repeated identical-F field=xvalues into a real array/repeated query param, matchingbuildRawQueryParams()'s existing behavior.key[]=valuebracket syntax for GET query building (stripping the brackets and merging into a repeat), or make it a validation error with a clear message instead of silently producing a mismatched literalfield[]param.-F/--fieldhelp text to clarify thatkey[]=valuearray-append semantics are body-only; document the correct GET multi-value syntax (repeat-F field=x, or a JSON-array value).via lorenzo.
--
View Junior Session [Sentry]