JuliusBrussee/caveman · error
sink %q not found in current learn plan
Error message
sink %q not found in current learn plan
What it means
applyLearnSink searched plan.Sinks for the given sink_id (exact string match on SinkID) and found nothing. The plan is rebuilt fresh inside this invocation (BuildLearnPlan over the current working directory and since-cutoff), so the id must exist in the plan as computed now, not in an older scan you read from.
Source
Thrown at proxy/cmd/caveman-proxy/main.go:629
Enabled: hasArg(args, "--retro"),
BehaviorBudgetMS: behaviorBudget,
BudgetMS: retroBudget,
}
}
// applyLearnSink materializes a candidate edit for a reducible sink under
// ~/.caveman/candidates/ and returns it. It never edits user config files itself —
// the analyzer is read-only; the consent-gated editing skill performs real edits.
func applyLearnSink(logger *slog.Logger, home, sinkID string, dryRun bool, plan store.LearnPlan) {
var target *store.Sink
for i := range plan.Sinks {
if plan.Sinks[i].SinkID == sinkID {
target = &plan.Sinks[i]
break
}
}
if target == nil {
fatalJSON(logger, fmt.Errorf("sink %q not found in current learn plan", sinkID))
}
var candidate map[string]any
switch target.Class {
case "reducible":
candidate = map[string]any{
"sink_id": sinkID,
"title": target.Title,
"class": target.Class,
"expected_tokens_per_turn_saved": target.TokensPerTurn,
"suggestion": target.Suggestion,
"evidence": target.Evidence,
"net_token_negative_gate": "the editing skill must measure before>after tokens/turn and reject any edit that does not reduce them",
"basis": plan.Basis,
}
case "recurring_context":
candidate = offloadCandidate(sinkID, target, plan.Basis, plan.Window.Since)
default:
printJSON(map[string]any{View on GitHub (pinned to 27d5a3981a)
Solutions
- Re-run caveman-proxy learn scan (same cwd and --since you will use for apply) and copy the sink_id exactly from that output
- Run learn apply <sink_id> --dry-run with the freshly scanned id to confirm the match before the real run
- Keep scan and apply in the same script/cwd so the plan cannot drift between them
Example fix
# before (id from an old scan, different cwd) cd ~/other && caveman-proxy learn apply old-sink-42 # after (rescan in the target cwd, use current id) cd ~/project && caveman-proxy learn scan caveman-proxy learn apply compress-stdin --dry-run
Defensive patterns
Strategy: validation
Validate before calling
PLAN=$(caveman-proxy learn scan --json) SINK_ID=$(echo "$PLAN" | jq -r '.sinks[0].sink_id') [ -n "$SINK_ID" ] && caveman-proxy learn apply "$SINK_ID" --dry-run
Prevention
- Re-scan in the same cwd and with the same --since immediately before apply
- Treat scanned sink lists as perishable — files/config changes reshape the plan
- Copy ids verbatim; they are exact-match, case-sensitive strings
When it happens
Trigger: Passing a sink id from a previous learn scan after the underlying files/config changed and the sink no longer registers; typo'd or case-mismatched id; running apply from a different cwd than the scan (sinks are cwd-relative), or with a different --since window that excludes the sink's evidence.
Common situations: Scan in one directory, apply in another; stale sink list pasted from yesterday's output; --since tightened so the sink's tokens no longer cross the threshold and it drops out of the plan.
Related errors
- optimizer %q not found in trial %s
- no trial_id supplied and no trial runs exist
- cave_harness_request_invalid
- cave_eve_terminal_${result.status}
- unknown command ${JSON.stringify(command)}; run caveman-agen
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/2e63a6d30b5170ce.
Report an issue: GitHub.