JuliusBrussee/caveman · error
arm must be %q or %q
Error message
arm must be %q or %q
What it means
Input validation guard in SwitchExperimentArm: the requested arm string was not one of the two allowed values (on/off) after lowercasing and trimming. It fires whenever a caller passes a typo, mixed-case value, or any arm name other than the two sentinel constants.
Source
Thrown at proxy/internal/store/learn_experiment.go:118
}
id, err := result.LastInsertId()
if err != nil {
return Experiment{}, fmt.Errorf("read experiment id: %w", err)
}
if _, err := s.db.Exec(`INSERT INTO experiment_arms (experiment_id, arm, started_at)
VALUES (?, ?, ?)`, id, experimentArmOn, now); err != nil {
return Experiment{}, fmt.Errorf("open first arm: %w", err)
}
return s.LoadExperiment(label)
}
// SwitchExperimentArm closes the open arm and opens the other one. Switching to
// the arm already running is a no-op rather than an error: it keeps a repeated
// call from fragmenting the interval history.
func (s *Store) SwitchExperimentArm(label, arm string) (Experiment, error) {
arm = strings.ToLower(strings.TrimSpace(arm))
if arm != experimentArmOn && arm != experimentArmOff {
return Experiment{}, fmt.Errorf("arm must be %q or %q", experimentArmOn, experimentArmOff)
}
experiment, err := s.LoadExperiment(label)
if err != nil {
return Experiment{}, err
}
if experiment.StoppedAt != "" {
return Experiment{}, fmt.Errorf("experiment %q is stopped", experiment.Label)
}
for _, existing := range experiment.Arms {
if existing.EndedAt == "" && existing.Arm == arm {
return experiment, nil
}
}
now := learnOutcomeClock().UTC().Format(time.RFC3339)
if _, err := s.db.Exec(`UPDATE experiment_arms SET ended_at = ?
WHERE experiment_id = ? AND ended_at IS NULL`, now, experiment.id); err != nil {
return Experiment{}, fmt.Errorf("close open arm: %w", err)
}View on GitHub (pinned to 81536f57b3)
Solutions
- Pass exactly "on" or "off" as the arm argument
- Normalize the arm string with strings.ToLower and strings.TrimSpace before calling
- Check the CLI flag or config value that supplied the arm name for typos
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at proxy/internal/store/learn_experiment.go:118 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of JuliusBrussee/caveman@81536f57b3 (2026-08-27).
Data as JSON: /api/errors/51638d0c6d3ca985.
Report an issue: GitHub.