Summary
cdidx's CLI argument validation for numeric flags (--limit, --snippet-lines, possibly others) is non-fatal: the command prints Error: --limit requires a positive integer, got 'X', but then silently falls back to the default value (20 for --limit) and produces normal output with exit code 0 (success).
AI consumers running --count preflight ("is it safe to fetch all results?") get:
- an
Error: line mixed in with the numeric result on stdout/stderr
- the reported count is the default-limit-capped number, not the user-requested count
- exit code = 0 (success) — scripts branching on exit code trust the output
This is the same trust-signal-lies family as #159 (--count silently capped at --limit) but for invalid --limit values specifically.
Repro
curl -fsSL https://raw.githubusercontent.com/Widthdom/CodeIndex/main/install.sh | bash
CDIDX=/root/.local/bin/cdidx
# Index any project so there's something to search
git clone https://github.com/tokio-rs/tokio /tmp/tokio
"$CDIDX" /tmp/tokio --db /tmp/tokio.db
Smoking gun — --limit -1 --count
OUT=$("$CDIDX" search spawn --db /tmp/tokio.db --limit -1 --count 2>&1); EC=$?
echo "OUTPUT:"; echo "$OUT"; echo "EXIT=$EC"
Observed:
OUTPUT:
Error: --limit requires a positive integer, got '-1'
14
EXIT=0
The command prints an Error: line and a number (14), exits with 0. The 14 is the count with the DEFAULT --limit=20, NOT the user's -1. AI agents that parse the last line of stdout treat 14 as the answer.
Same shape reproduces for other numeric flags / other invalid values
# --limit abc (non-numeric)
"$CDIDX" search spawn --db /tmp/tokio.db --limit abc 2>&1 | head -2; echo exit=$?
# Error: --limit requires a positive integer, got 'abc'
# tokio/src/task/spawn.rs:141-215 ← full result set still printed
# exit=0
# --limit 0
"$CDIDX" search spawn --db /tmp/tokio.db --limit 0; echo exit=$?
# Error: --limit requires a positive integer, got '0'
# ...results...
# exit=0
# --limit 99999999999999 (overflow)
"$CDIDX" search spawn --db /tmp/tokio.db --limit 99999999999999; echo exit=$?
# Error: --limit requires a positive integer, got '99999999999999'
# ...results...
# exit=0
# --snippet-lines -1
"$CDIDX" search spawn --db /tmp/tokio.db --snippet-lines -1; echo exit=$?
# Error: --snippet-lines requires a positive integer, got '-1'
# ...results...
# exit=0
All five variants print an error message and still produce successful output with exit code 0.
Related arg-parser edge cases (same session)
-
--db=value (equal-sign form) is silently rejected.
$CDIDX status --db=/tmp/tokio.db; echo exit=$?
# Warning: unknown option '--db=/tmp/tokio.db' (ignored)
# Error: database not found at /home/user/CodeIndex/.cdidx/codeindex.db ← defaulted
# exit=3
Users coming from git / gcc / dotnet conventions where --flag=value and --flag value are interchangeable hit this. The resulting "database not found" error is confusing — the user did supply a --db, cdidx just didn't parse it.
-
Unknown flags warn, don't error.
$CDIDX search spawn --db /tmp/tokio.db --nonexistent-flag foo; echo exit=$?
# Warning: unknown option '--nonexistent-flag' (ignored)
# ...normal search results...
# exit=0
Typos and renamed flags in user scripts become silent no-ops.
-
--limit with a flag-shaped value (e.g. user forgot the value) consumes the next flag as the "value" and errors:
$CDIDX search spawn --db /tmp/tokio.db --limit --lang rust; echo exit=$?
# Error: --limit requires a positive integer, got '--lang'
# ...search results (default limit)...
# exit=0
The --lang rust was intended as a separate filter but got consumed by --limit, and rust is left dangling. Again: error + success output + exit 0.
-
--limit at end of args (no value follows) emits "unknown option '--limit'" — wrong wording (it's a known option, just missing its value).
-
Duplicate --db /A.db --db /B.db silently uses the second without warning.
Suspected root cause
Likely in src/CodeIndex/Cli/ArgHelper.cs / QueryCommandRunner.cs: the numeric parser writes to stderr but returns a fallback default rather than propagating a failure signal. The command continues.
Non-fatal validation is often intentional for warnings, but for a typed numeric argument it should be an error: the user asked for something specific, the tool didn't honor it, the output doesn't match the request, yet exit is success.
Why it matters
Suggested direction
-
Return CommandExitCodes.UsageError (1) on any numeric-arg validation failure. Don't print results after an error line; either honor the default with a warning (and a different exit) or refuse to run.
-
Accept --flag=value form alongside --flag value. The parser can split on the first = when the flag is known to take a value.
-
Treat unknown flags as errors by default. Keep an opt-in --ignore-unknown-options if there's a real use case, but the default should fail fast so typos surface immediately.
-
"known option, missing value" is distinct from "unknown option" — say so. --limit at end of args should error with "--limit requires a value" not "unknown option '--limit'".
-
Warn on duplicate value-taking flags. At minimum emit a note: Warning: --db specified twice; using '/tmp/B.db'.
Scope
src/CodeIndex/Cli/ArgHelper.cs — core parser. Add exit-on-validation-failure for numeric args; accept = form.
src/CodeIndex/Cli/QueryCommandRunner.cs — downstream handling.
tests/CodeIndex.Tests/QueryCommandRunnerTests.cs — fixtures for:
--limit -1 → exit 1, no result output
--limit abc → exit 1
--db=path → parsed the same as --db path
--unknown-flag foo → exit 1 (or opt-in to warn-only)
- Duplicate
--db → warn + use last (or error)
Related
Environment
- cdidx: v1.10.0 (installed via
install.sh).
- Any indexed project reproduces.
tokio-rs/tokio@master used as the query target above.
- Platform: linux-x64 container.
- Filed from a cloud Claude Code session per
CLOUD_BOOTSTRAP_PROMPT.md.
Summary
cdidx's CLI argument validation for numeric flags (--limit,--snippet-lines, possibly others) is non-fatal: the command printsError: --limit requires a positive integer, got 'X', but then silently falls back to the default value (20 for--limit) and produces normal output with exit code 0 (success).AI consumers running
--countpreflight ("is it safe to fetch all results?") get:Error:line mixed in with the numeric result on stdout/stderrThis is the same trust-signal-lies family as #159 (
--countsilently capped at--limit) but for invalid--limitvalues specifically.Repro
Smoking gun —
--limit -1 --countObserved:
The command prints an
Error:line and a number (14), exits with 0. The14is the count with the DEFAULT--limit=20, NOT the user's-1. AI agents that parse the last line of stdout treat14as the answer.Same shape reproduces for other numeric flags / other invalid values
All five variants print an error message and still produce successful output with exit code 0.
Related arg-parser edge cases (same session)
--db=value(equal-sign form) is silently rejected.Users coming from git / gcc / dotnet conventions where
--flag=valueand--flag valueare interchangeable hit this. The resulting "database not found" error is confusing — the user did supply a--db, cdidx just didn't parse it.Unknown flags warn, don't error.
Typos and renamed flags in user scripts become silent no-ops.
--limitwith a flag-shaped value (e.g. user forgot the value) consumes the next flag as the "value" and errors:The
--lang rustwas intended as a separate filter but got consumed by--limit, andrustis left dangling. Again: error + success output + exit 0.--limitat end of args (no value follows) emits "unknown option '--limit'" — wrong wording (it's a known option, just missing its value).Duplicate
--db /A.db --db /B.dbsilently uses the second without warning.Suspected root cause
Likely in
src/CodeIndex/Cli/ArgHelper.cs/QueryCommandRunner.cs: the numeric parser writes to stderr but returns a fallback default rather than propagating a failure signal. The command continues.Non-fatal validation is often intentional for warnings, but for a typed numeric argument it should be an error: the user asked for something specific, the tool didn't honor it, the output doesn't match the request, yet exit is success.
Why it matters
--count) is unreliable.symbols --count/search --countreturnmin(total, limit)instead of the true row total, breaking AI preflight #159 already documents that--countsilently caps at--limit. This finding shows that on a bad--limitvalue the same cap is applied silently. Two separate ways to get a wrong count with exit 0.--flag=value. The silent "unknown option" + later "file not found" wastes debugging time.Suggested direction
Return
CommandExitCodes.UsageError(1) on any numeric-arg validation failure. Don't print results after an error line; either honor the default with a warning (and a different exit) or refuse to run.Accept
--flag=valueform alongside--flag value. The parser can split on the first=when the flag is known to take a value.Treat unknown flags as errors by default. Keep an opt-in
--ignore-unknown-optionsif there's a real use case, but the default should fail fast so typos surface immediately."known option, missing value" is distinct from "unknown option" — say so.
--limitat end of args should error with "--limitrequires a value" not "unknown option '--limit'".Warn on duplicate value-taking flags. At minimum emit a note:
Warning: --db specified twice; using '/tmp/B.db'.Scope
src/CodeIndex/Cli/ArgHelper.cs— core parser. Add exit-on-validation-failure for numeric args; accept=form.src/CodeIndex/Cli/QueryCommandRunner.cs— downstream handling.tests/CodeIndex.Tests/QueryCommandRunnerTests.cs— fixtures for:--limit -1→ exit 1, no result output--limit abc→ exit 1--db=path→ parsed the same as--db path--unknown-flag foo→ exit 1 (or opt-in to warn-only)--db→ warn + use last (or error)Related
symbols --count/search --countreturnmin(total, limit)instead of the true row total, breaking AI preflight #159 —--countsilently capped at--limit. Same family: the numeric value the user sees doesn't correspond to what they asked for, and exit=0 blesses it.backfill-fold --jsonaborts with SIGABRT (exit 134) and a .NET stack trace on the trimmed release —WriteCommandErrorand the success-pathJsonSerializer.Serialize(new { ... })both throw uncaught #181 —backfill-fold --jsonSIGABRT. Adjacent family: CLI error paths don't behave consistently.Environment
install.sh).tokio-rs/tokio@masterused as the query target above.CLOUD_BOOTSTRAP_PROMPT.md.