JuliusBrussee/caveman · error
at least one sink id is required
Error message
at least one sink id is required
What it means
simulateLearnPlan requires at least one sink id after deduplication of the requested selection. An empty selection means there is nothing to simulate, so it returns an explicit error instead of an empty simulation report. The check happens after collecting unique ids, so passing duplicates that all dedupe to nothing still triggers it.
Solutions
- Pass at least one valid sink id to the simulation call
- Default the CLI to the full plan when no explicit selection is given
- Guard your script: exit early with usage help if the selection list is empty
Example fix
// before
ids := os.Getenv("SINKS")
store.BuildLearnSimulationFiltered(plan, strings.Split(ids, ","))
// after
ids := os.Getenv("SINKS")
if strings.TrimSpace(ids) == "" {
return fmt.Errorf("set SINKS to at least one sink id")
}
store.BuildLearnSimulationFiltered(plan, strings.Split(ids, ",")) Defensive patterns
Strategy: validation
Validate before calling
cleaned := make([]string, 0, len(ids))
for _, id := range ids {
if id = strings.TrimSpace(id); id != "" { cleaned = append(cleaned, id) }
}
if len(cleaned) == 0 { return fmt.Errorf("supply at least one sink id to simulate") } Prevention
- Validate and dedupe the sink selection before invoking the simulation
- Default empty selections to the full plan in your wrapper
- Treat the selection flag as required in CLI help and shell completions
- Fail fast in scripts when a selection env var is unset or blank
When it happens
Trigger: Calling BuildLearnSimulationFiltered with an empty or nil sink id slice, or with a selection that contains no valid entries after dedup.
Common situations: Scripting the CLI with a variable that ends up empty; passing only whitespace/blank ids; wiring automation that forwards an optional flag with no value.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- at least one report path and the canonical span fixture…
- base and head must be full Git object IDs
- cave_live_eval_sandbox_profile_invalid
- caveman agent: entry must export default agent()
- --days must be an integer from 0 to 3660
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/8e34eca050bce878.
Report an issue: GitHub.
Appendix: source
Thrown at proxy/internal/store/learn_simulate.go:73
for _, sink := range plan.Sinks {
byID[sink.SinkID] = sink
}
unique := map[string]bool{}
for _, id := range sinkIDs {
id = strings.TrimSpace(id)
if id != "" {
unique[id] = true
}
}
ids := make([]string, 0, len(unique))
for id := range unique {
if _, ok := byID[id]; !ok {
return LearnSimulation{}, fmt.Errorf("sink %q not found in current learn plan", id)
}
ids = append(ids, id)
}
if len(ids) == 0 {
return LearnSimulation{}, fmt.Errorf("at least one sink id is required")
}
sort.Strings(ids)
// One owner per config file/family. Prefer broader measured weight, then sink
// id, so overlap refusal is stable regardless of CLI argument order.
owners := map[string]string{}
for _, id := range ids {
sink := byID[id]
key := simulationOverlapKey(sink)
if key == "" {
continue
}
owner, exists := owners[key]
if !exists || sink.TokensPerTurn > byID[owner].TokensPerTurn ||
(sink.TokensPerTurn == byID[owner].TokensPerTurn && id < owner) {
owners[key] = id
}
}View on GitHub (pinned to 3ee70a1026)