JuliusBrussee/caveman · error

usage: caveman-proxy learn apply <sink_id> [--dry-run]

Error message

usage: caveman-proxy learn apply <sink_id> [--dry-run]

What it means

The `learn apply` subcommand requires a sink_id positional and none was found. fatalJSON prints this usage line (which also documents the optional --dry-run flag) and exits 1 before BuildLearnPlan runs.

Source

Thrown at proxy/cmd/caveman-proxy/main.go:595

			fatalJSON(logger, err)
		}
		out := argFlag(args, "--out", store.DefaultLearnReportPath(home))
		if err := spend.WriteLearnHTML(plan, out); err != nil {
			fatalJSON(logger, err)
		}
		sidecar, err := spend.WriteLearnSidecars(home, plan, time.Now(), "")
		if err != nil {
			fatalJSON(logger, err)
		}
		if hasArg(args, "--json") {
			printJSON(plan)
			return
		}
		printJSON(map[string]any{"report": out, "sidecar": sidecar, "cave_score": plan.CaveScore.Score, "basis": plan.Basis, "sinks": len(plan.Sinks)})
	case "apply":
		sinkID := firstPositional(args)
		if sinkID == "" {
			fatalJSON(logger, fmt.Errorf("usage: caveman-proxy learn apply <sink_id> [--dry-run]"))
		}
		plan, err := spend.BuildLearnPlan(cwd, sources, since)
		if err != nil {
			fatalJSON(logger, err)
		}
		applyLearnSink(logger, home, sinkID, hasArg(args, "--dry-run"), plan)
	default:
		fatalJSON(logger, fmt.Errorf("unknown learn subcommand: %s", sub))
	}
}

func learnRetroOptions(args []string) store.RetroOptions {
	behaviorBudget, _ := strconv.Atoi(argFlag(args, "--behavior-budget-ms", "0"))
	retroBudget, _ := strconv.Atoi(argFlag(args, "--retro-budget-ms", "0"))
	return store.RetroOptions{
		Enabled:          hasArg(args, "--retro"),
		BehaviorBudgetMS: behaviorBudget,
		BudgetMS:         retroBudget,

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. First run learn scan to list sink ids, then pass one: caveman-proxy learn apply <sink_id> --dry-run
  2. Quote shell variables and assert non-empty in scripts
  3. Prefer a --dry-run first run to validate the sink id cheaply

Example fix

# before
caveman-proxy learn apply --dry-run

# after
caveman-proxy learn scan            # find sink ids
caveman-proxy learn apply compress-stdin --dry-run
Defensive patterns

Strategy: validation

Validate before calling

if [ -z "$SINK_ID" ]; then echo "sink id required (see: caveman-proxy learn scan)" >&2; exit 2; fi
caveman-proxy learn apply "$SINK_ID" --dry-run

Prevention

When it happens

Trigger: `caveman-proxy learn apply --dry-run` with no sink id; flags parsed first leaving no positional; empty SINK shell variable.

Common situations: Copy-pasting the example from the apply docs but dropping the id; assuming apply applies all sinks when none given (it does not — one sink per invocation); quoting bugs eating the argument.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/d63e40dfbc7acf02. Report an issue: GitHub.