{"record":{"id":"b2142f78c6f7d922","repo":"JuliusBrussee/caveman","slug":"open-first-arm-w","errorCode":null,"errorMessage":"open first arm: %w","messagePattern":"open first arm: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/internal/store/learn_experiment.go","lineNumber":107,"sourceCode":"\tif label == \"\" || len(label) > 128 {\n\t\treturn Experiment{}, fmt.Errorf(\"experiment label must be 1-128 bytes\")\n\t}\n\tif len(note) > 4096 {\n\t\treturn Experiment{}, fmt.Errorf(\"note exceeds 4096 bytes\")\n\t}\n\tnow := learnOutcomeClock().UTC().Format(time.RFC3339)\n\tresult, err := s.db.Exec(`INSERT INTO experiments (label, sink_id, fix_kind, note, created_at)\n\t\tVALUES (?, ?, ?, ?, ?)`, label, sinkID, fixKind, note, now)\n\tif err != nil {\n\t\treturn Experiment{}, fmt.Errorf(\"start experiment %q: %w\", label, err)\n\t}\n\tid, err := result.LastInsertId()\n\tif err != nil {\n\t\treturn Experiment{}, fmt.Errorf(\"read experiment id: %w\", err)\n\t}\n\tif _, err := s.db.Exec(`INSERT INTO experiment_arms (experiment_id, arm, started_at)\n\t\tVALUES (?, ?, ?)`, id, experimentArmOn, now); err != nil {\n\t\treturn Experiment{}, fmt.Errorf(\"open first arm: %w\", err)\n\t}\n\treturn s.LoadExperiment(label)\n}\n\n// SwitchExperimentArm closes the open arm and opens the other one. Switching to\n// the arm already running is a no-op rather than an error: it keeps a repeated\n// call from fragmenting the interval history.\nfunc (s *Store) SwitchExperimentArm(label, arm string) (Experiment, error) {\n\tarm = strings.ToLower(strings.TrimSpace(arm))\n\tif arm != experimentArmOn && arm != experimentArmOff {\n\t\treturn Experiment{}, fmt.Errorf(\"arm must be %q or %q\", experimentArmOn, experimentArmOff)\n\t}\n\texperiment, err := s.LoadExperiment(label)\n\tif err != nil {\n\t\treturn Experiment{}, err\n\t}\n\tif experiment.StoppedAt != \"\" {\n\t\treturn Experiment{}, fmt.Errorf(\"experiment %q is stopped\", experiment.Label)","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/81536f57b3303b7de7f5bc5b564cc344f9112d68/proxy/internal/store/learn_experiment.go#L89-L125","documentation":"SQLite insert of the initial experiments row failed while starting a learn experiment, so the experiment could not be created at all. It fires only on a database-level failure (locked DB, disk error, schema mismatch), not on invalid input, which is validated earlier.","triggerScenarios":"Thrown at proxy/internal/store/learn_experiment.go:107 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Check the SQLite database file is writable and not locked by another process","Inspect the wrapped underlying driver error for the real cause (e.g. disk I/O, corruption)","Retry StartExperiment once the database is available","Verify the experiments table schema matches the INSERT column list"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"81536f57b3303b7de7f5bc5b564cc344f9112d68","analyzedAt":"2026-08-27T02:25:50.681Z","contentChangedAt":"2026-08-27T02:25:50.681Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}