ErrLookup › Background articles › "Unknown argument", "Invalid value", and "must be one of": invalid CLI argument errors explained
"Unknown argument", "Invalid value", and "must be one of": invalid CLI argument errors explained
Invalid CLI argument errors — messages like "Unknown argument", "invalid value", "must be one of", "expected ... got ...", or "Invalid filter" — are thrown at the argument-parsing layer of a CLI before any real work runs. This article covers why these validators exist, the recurring triggers across libraries (typos, wrong separators, missing values, empty shell variables, dangling flags), and the general strategies for fixing and preventing them.
Distilled from 85 documented records across 35 repositories.
Background
Invalid-CLI-argument errors are produced at the very front door of a tool: the argument parser or an immediately-following validation pass rejects your invocation before a single unit of real work happens. That is their defining property across the family. Phabricator's PhutilArgumentUsageException aborts bin/mail send-test before doing anything; RuboCop raises IncorrectCopNameError during option validation; sglang's ServerArgs check fires during startup before any model loads; neon's storcon_cli FromStr impls fail during argument parsing, before any request reaches the storage controller. When you see this family, the invocation itself is wrong — no task failed, no data was touched.
The validators are deliberately strict because silently ignoring a bad flag is dangerous. ECC's auto-update parser refuses any token outside its five supported flags because a mistyped command could run a partial update. code-server refuses to start rather than silently dropping a malformed --vscode-option. Yeachan-Heo/oh-my-codex validates --keep-policy to prevent an unknown keep policy from breaking mission compilation later. The error you get is the cheap failure the authors chose over an expensive, confusing one downstream.
Under the hood the family shares a small set of parsing mechanics. Many validators are allowlists: a token must exactly match an enumerated vocabulary (deno's split-point kinds, neon's active/offline and active/essential/pause/stop, ECC's ito command list, freeCodeCamp's fuzzy-matched superblock and block names). Many are structural: the parser splits a value on a separator and requires the split to succeed — influxdb3's key=value tokens, Playwright's username:password, deno's @-separated package@version filters, Zed's user@distro split on the first '@'. Others are numeric range checks (career-ops' --limit 1..100 and --months 1..120, Phabricator's positive-integer priority, sglang's -1-or-positive sentinel) where a missing value becomes NaN or 0 and fails the check.
The caller-side experience varies by library. Some errors echo back your exact input and enumerate the accepted values in the message itself (fluentd's capability list, deno's dcore naming the flag and the parse failure, freeCodeCamp suggesting 'is that what you meant?'); others only point at --help (RuboCop's --show-cops, ECC's --help). Parsing conventions differ too: some parsers require the value attached with '=' (deno's dcore --inspect), while others consume the next argv token, which is exactly how a dangling flag at the end of the line or '--limit --json' swallows the wrong thing. Behavior on empty values, case sensitivity, and alias handling (career-ops normalizes and aliases hn but still rejects 'the-guardian') is library-specific — always check the record or --help for the exact contract.
Common causes
- Typo or wrong case in a value that must match an allowlist. Enumerated vocabularies are exact-match: rubocop --only Style/StringLterals, 'ecc ito Login', 'Active' for neon's lowercase active/offline, underscores instead of kebab-case in zed's split kinds. The fix is to copy the exact value from the error message's own list or from --help output.
- Missing or dangling flag value. When a parser consumes the next argv token, a flag at the end of the line or followed by another flag yields NaN, an empty string, or undefined: '--limit --json', '--months' as the last token, --mode with no value in expo's ExpoConfigLoader. Always pass the value as its own explicit token.
- Empty shell-variable expansion. An unset variable expands to nothing, shifting parsing onto the wrong token, or the parser sees an empty entry (code-server's --vscode-option "", VSCODE_OPTIONS tokens). Use "${VAR:?must be set}" so a blank variable fails with your own message before it corrupts parsing.
- Wrong separator in a structured value. Split-based parsers fail when the separator is absent or wrong: 'foo=^2.0.0' instead of foo@^2.0.0 for deno outdated filters, --trigger-arguments foo with no '=' in influxdb3, --http-credentials=admin with no colon in Playwright, zed --wsl @Ubuntu with an empty user. Values must match the documented shape, separator included.
- Out-of-range or non-integer numeric values. Numeric flags enforce ranges and integrality: career-ops rejects --limit 0 or 150 and --months 2y, Phabricator rejects priority 0 or negative, sglang only accepts -1 or a positive integer for --mamba-max-states-per-path. Non-numeric text often becomes 0 or NaN via an int cast and fails the same check.
- Too many or misplaced positional arguments. Parsers that accept a fixed number of positionals reject the rest: two directories to ECC's gemini-adapt-agents (often from an unquoted path containing a space), a second positional after 'catalog.js show <id>', or a positional under a command that takes none. Quote paths and pass only the positionals the command documents.
- Wrong flag name for the tool invoked. The flag belongs to a different tool or surface: 'ecc ito run' when the wrapper only proxies a closed command list, --profile passed to ECC's auto-update (it belongs to install-apply.js), plural '--targets' instead of singular '--target', or a source id like 'crunchbase' that career-ops never wired up.
- Stale value after a rename or restructure. Values that used to be valid stop being so: a RuboCop cop renamed or removed in an upgrade, a freeCodeCamp block renamed in a curriculum restructure, a custom cop whose file was never required so it is not registered. Re-copy names from the current source of truth (registry output, structure files, enum) after upgrades.
What usually fixes it
- [object Object]
- [object Object]
- [object Object]
- [object Object]
Documented occurrences
- --vscode-option requires a flag name (got "${entry}") (coder/code-server)
- Message type "%s" is unknown, supported message types are: %s. (phacility/phabricator)
- Priority must be a positive integer. (phacility/phabricator)
- Unsupported Itô command "${command || "(missing)"}"; ECC permits only login, logout, auth, find, status, and evals. (affaan-m/ECC)
- Invalid source: expected an uncommitted file or branch (gitbutlerapp/gitbutler)
- "${color.bold(template)}" is an invalid template. Run ${color.bold("create-react-router --help")} to see supported template formats. (remix-run/react-router)
- must be formatted as "key=value" (influxdata/influxdb)
- Expected at most one agents directory argument (affaan-m/ECC)
- Invalid filter "{input}" (denoland/deno)
- Unknown argument: ${arg} (affaan-m/ECC)
- unknown source in --sources: ${source} (santifer/career-ops)
- No close match found for superBlock: ${target.superBlock}. Found "${closest}", is that what you meant? (freeCodeCamp/freeCodeCamp)
- --keep-policy must be one of: score_improvement, pass_only (Yeachan-Heo/oh-my-codex)
- --limit must be an integer from 1 to 100 (santifer/career-ops)
- invalid split point kind '{value}' (expected fim, same-file-near, same-file-far, or cross-file) (zed-industries/zed)
- Unknown argument: ${arg} (affaan-m/ECC)
- Unrecognized cop or department: %<name>s. (rubocop/rubocop)
- '#{capability}' is not valid capability. Valid Capabilities are: #{valid_capabilities.join(", ")} (fluent/fluentd)
- Invalid http credentials format: use "username:password", for example --http-credentials="admin:secret" (microsoft/playwright)
- invalid line (facebook/flow)
…and 65 more across the corpus — use search.
Honest provenance: generated on 2026-08-28 from AI-assisted analysis of the linked records. See how records are made.