JuliusBrussee/caveman · error
unknown learn subcommand
Error message
unknown learn subcommand: %s
What it means
Thrown by runLearn's default branch when the first argument is not one of scan|report|savings|apply|applied|simulate. Note `learn` defaults to `scan` when no subcommand is given, so this only fires for a non-empty unrecognized subcommand.
Solutions
- Use one of: `caveman-proxy learn scan|report|savings|apply|applied|simulate`.
- Run bare `caveman-proxy learn` — it defaults to `scan` and shows what the scan path does.
- Check spelling, especially apply vs applied which are both valid but mean different things.
Example fix
// before caveman-proxy learn analyze // after caveman-proxy learn scan
Defensive patterns
Strategy: validation
Validate before calling
// shell case "$SUB" in scan|report|savings|apply|applied|simulate) ;; *) echo "learn subcommands: scan|report|savings|apply|applied|simulate" >&2; exit 2;; esac caveman-proxy learn "$SUB" "$@"
Prevention
- Valid subcommands: scan, report, savings, apply, applied, simulate (default is scan).
- Note apply vs applied are distinct — check spelling.
- Consult --help rather than guessing names.
When it happens
Trigger: `caveman-proxy learn analyze`, `learn optimise` (typo), `learn list`, or any misspelling of the six valid subcommands.
Common situations: Guessing subcommand names (`learn suggestions`, `learn fixes`); mixing up singular/plural (`apply` vs `applied` are distinct subcommands); scripts ported from an older CLI layout.
Understand the failure class
Background: "Unknown argument", "Invalid value", and "must be one of": invalid CLI argument errors explained — this error's family across 35 libraries.
Related errors
- sink not found in current learn plan
- unknown trial subcommand
- unknown usage subcommand
- usage: caveman-proxy learn applied
- usage: caveman-proxy learn apply
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/871e58d23d40414f.
Report an issue: GitHub.
Appendix: source
Thrown at proxy/cmd/caveman-proxy/main.go:761
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,
}
func learnSinkPositionals(args []string) []string {
var ids []string
for i := 0; i < len(args); i++ {
arg := args[i]
if strings.HasPrefix(arg, "--") {
if !strings.Contains(arg, "=") && positionalValueFlags[arg] && i+1 < len(args) {View on GitHub (pinned to 3ee70a1026)