JuliusBrussee/caveman · error
usage: caveman-proxy learn simulate
Error message
usage: caveman-proxy learn simulate <sink_id> [<sink_id>...] [--sources <list>] [--since <window>]
What it means
Thrown by runLearn's `simulate` branch when learnSinkPositionals(args) yields no ids: `learn simulate <sink_id> [<sink_id>...] [--sources <list>] [--since <window>]`. Simulation evaluates estimated savings for one or more sinks, so at least one positional id is required.
Solutions
- Pass at least one bare sink id: `caveman-proxy learn simulate <sink_id>`.
- Pass multiple ids space-separated after the subcommand, flags can come before or after: `learn simulate id1 id2 --sources claude --since 30d`.
- Verify the id list is non-empty in scripts before calling the CLI.
Example fix
// before caveman-proxy learn simulate --sources claude // after caveman-proxy learn simulate context-overload-7f3a pixel-sink-9b1c --sources claude --since 30d
Defensive patterns
Strategy: validation
Validate before calling
// shell IDS=$(learnSinkPositionals "$@") # bare non-flag args only if [ -z "$IDS" ]; then echo "learn simulate needs at least one sink_id" >&2; exit 2; fi caveman-proxy learn simulate $IDS --sources claude --since 30d
Prevention
- Only bare words count as ids; flag values like --sources claude are ignored by the positional parser.
- In batch pipelines assert the id array is non-empty before invoking.
- Pass multiple ids space-separated.
When it happens
Trigger: `caveman-proxy learn simulate` bare; `learn simulate --sources claude --since 30d` where all args are flags; accidentally quoting ids into the flag values so no bare positionals remain.
Common situations: Batch-simulating sinks in a pipeline where the id list variable expanded to empty; forgetting that flag values like `--sources claude` are skipped by learnSinkPositionals and only bare words count as ids.
Understand the failure class
Background: "no subcommand specified" and "... is required": CLI errors when a required argument is missing — this error's family across 13 libraries.
Related errors
- usage: caveman-proxy learn applied
- usage: caveman-proxy learn apply
- no trial_id supplied and no trial runs exist
- sink not found in current learn plan
- unknown learn subcommand
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/7e11a92de3605e60.
Report an issue: GitHub.
Appendix: source
Thrown at proxy/cmd/caveman-proxy/main.go:753
applyLearnSink(logger, home, sinkID, hasArg(args, "--dry-run"), plan)
case "applied":
sinkID := firstPositional(args)
if sinkID == "" {
fatalJSON(logger, fmt.Errorf("usage: caveman-proxy learn applied <sink_id> [--fix-kind <k>] [--note <s>]"))
}
plan, err := spend.BuildLearnPlanFilteredWithRetro(cwd, sources, since, store.RetroOptions{}, repoFilter)
if err != nil {
fatalJSON(logger, err)
}
recorded, err := spend.RecordAppliedFix(plan, sinkID, argFlag(args, "--fix-kind", ""), argFlag(args, "--note", ""))
if err != nil {
fatalJSON(logger, err)
}
printJSON(recorded)
case "simulate":
sinkIDs := learnSinkPositionals(args)
if len(sinkIDs) == 0 {
fatalJSON(logger, fmt.Errorf("usage: caveman-proxy learn simulate <sink_id> [<sink_id>...] [--sources <list>] [--since <window>]"))
}
simulation, err := spend.BuildLearnSimulationFiltered(cwd, sources, since, sinkIDs, repoFilter)
if err != nil {
fatalJSON(logger, err)
}
printJSON(simulation)
default:
fatalJSON(logger, fmt.Errorf("unknown learn subcommand: %s", sub))
}
}
var positionalValueFlags = map[string]bool{
"--agent": true, "--behavior-budget-ms": true, "--build": true,
"--command": true, "--decision": true, "--exit-code": true,
"--fix-kind": true, "--note": true, "--out": true, "--path": true,
"--plan": true, "--port": true, "--recent": true, "--repo": true,
"--retro-budget-ms": true, "--session": true, "--since": true,
"--sources": true, "--trial-id": true, "--write-report-token": true,View on GitHub (pinned to 3ee70a1026)