#2489·OpenCLI

[Bug]: -f with an unknown format silently renders a table instead of failing

Author: aborrusoCreated Sep 12, 2026Updated Sep 12, 2026

Description

-f/--format accepts any string. An unrecognised value is not rejected: render() falls through to the default: branch of its switch and prints a table, exit code 0. A script or an agent that asks for a format it believes exists gets tabular output with box-drawing characters and no indication that its request was ignored.

The closed set is advertised. --help prints choices: table, plain, json, yaml, md, csv, and that list is declared in COMMON_OPTIONS in src/help.js. Nothing enforces it.

The inconsistency is internal to the same option table: --trace, declared with choices in the same block, is enforced — by an explicit normaliser that throws ArgumentError, alongside normalizeSiteSession, normalizeBooleanOption and normalizeWindowMode in src/execution.js. --format has no equivalent.

This bites agents hardest, because the wrong output is still parseable-looking text rather than an error.

Steps to Reproduce

Reproduces on a core command, so it is not adapter-specific:

bash
$ opencli list -f bogus
  opencli/list
┌───────────────────────────────────┬───────────────────┬─── ... (a table)
$ echo $?
0

$ opencli list -f csv          # for contrast
command,site,name,aliases,description,access,strategy,browser,args
...
$ echo $?
0

Same on an adapter command, and next to --trace for comparison:

bash
$ opencli eur-lex get 32024R1689 --chars 10 -f bogus
  eur-lex/get
┌────────────┬────────────────┬──── ... (a table, exit 0)

$ opencli eur-lex get 32024R1689 --chars 10 --trace bogus
ok: false
error:
  code: ARGUMENT
  message: '--trace must be one of: off, on, retain-on-failure. Received: "bogus"'
  exitCode: 2

Expected Behavior

-f bogus should fail the way --trace bogus already does: ArgumentError, exit 2, and a message naming the accepted values — --format must be one of: table, plain, json, yaml, md, csv. Received: "bogus".

The list already exists in COMMON_OPTIONS, so the fix can reuse it rather than restate it, which also keeps --help and the validation from drifting apart.

Two adjacent notes, both smaller than the above:

  1. render() also silently downgrades table to yaml when stdout is not a TTY. That behaviour is reasonable and documented in the code, but it means footerExtra disappears in every pipe — so an answer-level value put in the footer is unreachable to any non-interactive caller. Adapters can work around it by making the value a column; worth knowing when writing the guidance for adapter authors.
  2. Feature, separable from the bug: jsonl would be a welcome seventh format — one JSON object per line, no enclosing array. It is the natural shape for streaming into jq, duckdb read_ndjson_auto, or a line-oriented pipeline, and today it needs -f json | jq -c '.[]', which buffers the whole array first. renderJsonl is a four-line neighbour of renderCsv. Happy to open it as its own feature request if you would rather keep this issue to the bug.

OpenCLI Version

1.8.7

Environment

  • Node.js v24.18.0
  • Linux (WSL2), zsh