{"record":{"id":"3834b6258f528b12","repo":"chenhg5/cc-connect","slug":"invalid-session-mode-q-want-reuse-new-per-run-3834b6","errorCode":null,"errorMessage":"invalid session_mode %q (want reuse, new_per_run, or new-per-run)","messagePattern":"invalid session_mode %q \\(want reuse, new_per_run, or new-per-run\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/timer.go","lineNumber":75,"sourceCode":"\treturn NormalizeCronSessionMode(j.SessionMode) == \"new_per_run\"\n}\n\nfunc validateTimerJob(j *TimerJob) error {\n\tif strings.TrimSpace(j.SessionKey) == \"\" {\n\t\treturn fmt.Errorf(\"session_key is required\")\n\t}\n\tif j.ScheduledAt.IsZero() {\n\t\treturn fmt.Errorf(\"scheduled_at is required\")\n\t}\n\tif j.Prompt == \"\" && j.Exec == \"\" {\n\t\treturn fmt.Errorf(\"either prompt or exec is required\")\n\t}\n\tif j.Prompt != \"\" && j.Exec != \"\" {\n\t\treturn fmt.Errorf(\"prompt and exec are mutually exclusive\")\n\t}\n\tmode := NormalizeCronSessionMode(j.SessionMode)\n\tif mode != \"\" && mode != \"new_per_run\" {\n\t\treturn fmt.Errorf(\"invalid session_mode %q (want reuse, new_per_run, or new-per-run)\", j.SessionMode)\n\t}\n\tif j.Mode != \"\" {\n\t\tswitch j.Mode {\n\t\tcase \"default\", \"bypassPermissions\", \"acceptEdits\", \"plan\", \"auto\", \"dontAsk\":\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid mode %q\", j.Mode)\n\t\t}\n\t}\n\tif j.TimeoutMins != nil && *j.TimeoutMins < 0 {\n\t\treturn fmt.Errorf(\"timeout_mins must be >= 0\")\n\t}\n\treturn nil\n}\n\n// TimerStore persists timer jobs to a JSON file.\ntype TimerStore struct {\n\tpath string\n\tmu   sync.Mutex","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/timer.go#L57-L93","documentation":"validateTimerJob normalizes SessionMode via NormalizeCronSessionMode and accepts only \"\", \"reuse\", or \"new_per_run\" (the latter also spelled \"new-per-run\"). Any other SessionMode string is rejected by AddJob with the offending value quoted.","triggerScenarios":"AddJob with TimerJob.SessionMode set to an unrecognized value such as \"fresh\", \"always_new\", \"NEW_PER_RUN\" (if not normalized case-insensitively), or a typo like \"new_epr_run\".","commonSituations":"Users guessing mode names in config.toml; configs ported from a different scheduler with different mode vocabulary; case or hyphen/underscore variations of the valid values.","solutions":["Use SessionMode: \"reuse\" to keep using the same session across runs.","Use \"new_per_run\" (or \"new-per-run\") to start a fresh session for each run.","Leave SessionMode empty (\"\") to accept the default behavior.","Call core.NormalizeCronSessionMode on the value first and inspect what it maps to before AddJob."],"exampleFix":"// before\njob := &core.TimerJob{SessionKey: k, ScheduledAt: when, Prompt: p, SessionMode: \"fresh\"}\nsched.AddJob(job)\n// after\njob := &core.TimerJob{SessionKey: k, ScheduledAt: when, Prompt: p, SessionMode: \"new_per_run\"}\nsched.AddJob(job)","handlingStrategy":"validation","validationCode":"mode := core.NormalizeCronSessionMode(job.SessionMode)\nif mode != \"\" && mode != \"new_per_run\" { return fmt.Errorf(\"bad session_mode %q\", job.SessionMode) }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only assign SessionMode from the known set: reuse, new_per_run, new-per-run, or empty","Normalize user input through core.NormalizeCronSessionMode before storing","Validate session_mode values at config-load time"],"tags":["timer","validation","enum"],"backgroundTag":"invalid-enum-value","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}