Skip to content

search run --help advertises --stream detect, but the Search API rejects it #341

Description

@ethack

The problem in short:
limacharlie search run --help advertises --stream detect, but the Search API rejects that value with an explicit HTTP 400 — {'error': 'invalid stream value, valid values are: event, detection, audit'} every other subsystem in the client source lists detect (firehose, spout, outputs, Replay), and commands/stream.py#L232 even enforces that exact list with click.Choice.

The ask in short:
Could the spelling be made consistent across subsystems? Or at the very least, update any help strings that currently name detect but the API expects detection?


Inconsistent detect vs detection stream value: Search rejects detect, every other subsystem uses it

Package: limacharlie (PyPI)
Affected versions: runtime-reproduced on 5.6.1; the same code is present unchanged in 5.6.2 (latest at time of writing) and on master @ 54b0e9d — those two were verified by reading source, not by re-running.

All source permalinks below are pinned to refractionPOINT/python-limacharlie @ 54b0e9d7655b17ecca34cdcb42d2bb68b00de68a (default branch master) and refractionPOINT/documentation @ 3ffaf380975bf69a915ec8cffe32920ff970efc8. Line numbers are identical across 5.6.1, 5.6.2, and master.

Verification status. The only command actually executed against a live tenant is search run (§1). Everything else here — the search estimate / search saved-create behavior, the search validate gap, and the detect usage in other subsystems (§3) — is read from source and docs, not tested. Individual claims are marked where that distinction matters.


1. --stream detect is documented but rejected by the API

The option advertises three values, one of which the backend refuses.

limacharlie/commands/search.py#L1287

@click.option("--stream", default=None, help="Stream type (event, detect, audit).")

The long-form help topic repeats it and expands detect with detection-specific field names, which makes it read as authoritative — #L1205-L1208:

Streams:
  event   - sensor telemetry (NEW_PROCESS, DNS_REQUEST, etc.)
  detect  - D&R rule detections (has cat, detect, detect_id fields)
  audit   - platform management logs (has etype, msg, ident fields)

Reproduction

The API rejects it explicitly — an HTTP 400 whose body names the accepted values:

$ limacharlie search run --query '* | "Some Rule" | *' \
    --stream detect --oid <uuid> --start <epoch> --end <epoch>

Error: Failed to initiate search: API error (400): {'error': 'invalid stream value, valid values are: event, detection, audit'}

--stream detection works and returns results.

To be clear about severity: the backend behaves correctly and fails loudly — it returns a 400 and tells you exactly which values are valid. Nothing is silent or ambiguous at the API layer. The defect is confined to the CLI's help text (and the SDK docstring) naming a value the API refuses.

Why nothing catches it

There is no click.Choice on the option, so no client-side rejection, and the value reaches the API untranslated:

  • CLI → SDK, unmodified — commands/search.py#L1408
    gen = search.execute(query, start, end, stream=stream, limit=limit, progress_fn=progress_fn)
  • SDK → request body, unmodified — sdk/search.py#L281-L282
    if stream:
        body["stream"] = stream
  • The POST that 400s, and the wrapper producing the verbatim error above — sdk/search.py#L296-L297
  • The SDK docstring carries the same wrong vocabulary — sdk/search.py#L246: stream: Stream type ('event', 'detect', 'audit').

The same help string appears on two more commands

Not tested — the string is identical in source, but neither command was run:

Command Location
search estimate commands/search.py#L1972
search saved-create commands/search.py#L2076
saved-query explain text commands/search.py#L2059 — stream: event # optional (event, detect, audit)

Whether these two reject detect the same way search run does is unverified — we assume so, since the help text is the same and none of the three commands has a click.Choice, but that is inference from reading the code rather than an observed result. Worth a quick check on your side.

Similarly unverified: whether saved-create persists an invalid stream into the saved-query record and defers the failure to saved-run. That would be worse than the run case, because the error would be decoupled from the action that caused it — but we did not test it, and it is equally possible the value is validated at creation.


2. search validate has no --stream, though the SDK and backend accept one

commands/search.py#L1764-L1774

@group.command()
@click.option("--query", required=True, help="LCQL query string to validate.")
...
    data = search.validate(query)

--query is the command's only option, and the call drops the stream entirely — even though Search.validate() accepts a stream argument and puts it in the request body:

That the backend search/validate endpoint honors a stream field is inferred from the SDK sending it, not confirmed — we did not call the endpoint with a stream. Consequence, assuming it does: a query cannot be validated against the stream it will actually run on. (We also did not construct a case where validation passes but execution then fails on a stream mismatch, so the practical impact is unquantified.)

If the backend does accept it, the fix is CLI-side only — one @click.option plus threading it through.


3. detect is the spelling used elsewhere in the codebase

None of the subsystems below was tested — this section is a source-and-docs survey only. We are not claiming detect is accepted by their backends, only that it is the value their code and the docs list. The contrast with Search is what matters: the same three words appear repeatedly with no shared constant, and one of the three is invalid on the Search path.

The clearest example — the identical three-value list is enforced client-side here, and not enforced at all on the search path:

commands/stream.py#L232

type=click.Choice(["event", "detect", "audit"], case_sensitive=False),

Other places detect appears as the listed or passed value:

Docs confirm Replay's vocabulary is detect — documentation, docs/5-integrations/services/replay.md#L122:

    "stream": "" // defaults to events, can also be "audit" or "detect"

The word detection appears nowhere in the documentation as a stream value. Every Search/query example uses "stream": "event" only (docs/4-data-queries/index.md L75, L101, L248; docs/4-data-queries/query-limits-and-performance.md L126, L150, L380), and the docs never enumerate the Search API's accepted values. So the CLI help is currently the only place a user can obtain a value list for Search — and it is wrong.

Related docs gap: the search/validate REST example (docs/4-data-queries/index.md L109-L122) omits stream as well, mirroring the CLI gap in issue #3.


Suggested fix

Make detect / detection consistent everywhere. That is the real ask — the help-string mismatch is a symptom, and correcting only the help text would document the inconsistency rather than remove it. Concretely, in rough order of preference:

  1. Pick one spelling and use it across all subsystems. detect is the spelling that appears in the most places in the source (firehose, spout, outputs, Replay, and the stream firehose CLI), so having the Search API accept detect — as an alias at minimum — would align it with the rest and make the existing CLI help correct as written. If detection must stay canonical for Search, having the client translate would mean users only ever type one word. You are better placed than we are to say which spelling each backend genuinely requires — we only surveyed the client source.
  2. Share a single constant for the valid stream values instead of repeating the list in each module, so the subsystems cannot drift apart again. The list is currently duplicated in at least sdk/firehose.py, sdk/spout.py, commands/stream.py, commands/output_cmd.py, and three help strings in commands/search.py.
  3. Until (1) lands, fix the Search help string(s) (search run, search estimate, search saved-create) and the Search.execute docstring so they name the value the API actually accepts, and add click.Choice so a wrong value fails at the CLI with a clear message instead of a round-trip 400.
  4. Add --stream to search validate and pass it through — the SDK method already accepts one (backend support inferred, not confirmed), so a query could be validated against the stream it will run on.
  5. Document the Search API's accepted stream values. They are currently enumerated nowhere in the docs, which is why the (incorrect) CLI help is the only available reference.

Version notes

  • Latest on PyPI at time of writing: 5.6.2 (uploaded 2026-08-20).
  • The 5.6.2 wheel was unpacked and checked: commands/search.py:1287 and :1972 are byte-identical to 5.6.1, and validate at :1764-1767 still exposes only --query. Upgrading to 5.6.2 does not fix this.
  • master @ 54b0e9d — unchanged. Still present on the default branch.

Duplicate check — done, no duplicate

Checked 2026-08-26 against https://github.com/refractionPOINT/python-limacharlie/issues. The tracker holds 9 issues total across its entire history, so this was verified by full enumeration rather than by a keyword search alone (a keyword search for stream returns 0, and the search endpoint was control-tested to confirm that 0 is genuine).

All 9: #324, #237, #227, #226, #57, #32, #31, #30, #1. None concerns the --stream value or the detect/detection vocabulary. No open or closed PR addresses it either (searched stream, detection, click.Choice).

Two existing issues are worth referencing as related, though neither is a duplicate:

  • #237 (open, 2026-03-06) — "Cheatsheets and help topics reference non-existent 'rule' commands instead of 'dr'." Same class of defect: CLI help text naming commands/values that do not work (limacharlie rule list vs dr, fp create --name vs fp set --key). Good evidence that help-text drift is a recurring pattern here rather than a one-off, and that a shared source of truth would fix a category rather than an instance. Worth linking when filing.
  • #57 (open, 2022-10-02) — "Replay --validate fails" with {'error': 'no event_source specified'}. Structurally similar to item 2 above: a validate subcommand that cannot be given a parameter the backend requires. Open ~4 years.

Also note PR #263 (merged) — "fix: match help topic names to CLI command names" — precedent that this class of fix is accepted, and PR #247 (merged), which touched search error messages, so the surrounding code has had recent attention.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions