{"record":{"id":"d90f2ffa303ccd5b","repo":"chenhg5/cc-connect","slug":"invalid-mode-q","errorCode":null,"errorMessage":"invalid mode %q","messagePattern":"invalid mode %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/timer.go","lineNumber":81,"sourceCode":"\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\n\tjobs []*TimerJob\n}\n\nfunc NewTimerStore(dataDir string) (*TimerStore, error) {\n\tdir := filepath.Join(dataDir, \"timers\")\n\tif err := os.MkdirAll(dir, 0o755); err != nil {","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/timer.go#L63-L99","documentation":"validateTimerJob checks the optional TimerJob.Mode (permission mode for the agent run) against a fixed allowlist: \"default\", \"bypassPermissions\", \"acceptEdits\", \"plan\", \"auto\", \"dontAsk\". Any other non-empty string fails validation in AddJob.","triggerScenarios":"AddJob with TimerJob.Mode set to an unknown permission mode string, e.g. \"yolo\", \"acceptAll\", \"bypass\", or a value valid in a different tool but not in this allowlist.","commonSituations":"Copying a permission-mode name from another agent CLI; typos in config.toml; older configs using names that were later renamed into the current set.","solutions":["Set Mode to one of: \"default\", \"bypassPermissions\", \"acceptEdits\", \"plan\", \"auto\", \"dontAsk\".","Omit Mode entirely (empty string) to inherit the session's default permission mode.","Map legacy names in your config loader (e.g. \"yolo\" -> \"bypassPermissions\") before constructing the job.","Keep the allowlist in sync if new modes are added upstream and re-validate stored jobs."],"exampleFix":"// before\njob := &core.TimerJob{SessionKey: k, ScheduledAt: when, Prompt: p, Mode: \"yolo\"}\nsched.AddJob(job)\n// after\njob := &core.TimerJob{SessionKey: k, ScheduledAt: when, Prompt: p, Mode: \"bypassPermissions\"}\nsched.AddJob(job)","handlingStrategy":"validation","validationCode":"var validModes = map[string]bool{\"default\":true,\"bypassPermissions\":true,\"acceptEdits\":true,\"plan\":true,\"auto\":true,\"dontAsk\":true}\nif job.Mode != \"\" && !validModes[job.Mode] { return fmt.Errorf(\"bad mode %q\", job.Mode) }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep a shared allowlist constant instead of hand-typing mode strings in configs","Map legacy/foreign permission-mode names to the current set during config load","Copy mode strings from the reference docs verbatim, respecting case"],"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"}