{"record":{"id":"9c624346cc4112e1","repo":"chenhg5/cc-connect","slug":"session-key-is-required","errorCode":null,"errorMessage":"session_key is required","messagePattern":"session_key is required","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"core/cron.go","lineNumber":97,"sourceCode":"\tswitch low {\n\tcase \"\", \"reuse\":\n\t\treturn \"\"\n\tcase \"new_per_run\", \"new-per-run\":\n\t\treturn \"new_per_run\"\n\tdefault:\n\t\treturn s\n\t}\n}\n\nfunc validateCronJob(j *CronJob) error {\n\t// SessionKey anchors the cron execution to a platform (ExecuteCronJob\n\t// derives platformName from the prefix before \":\"). Without it the job\n\t// is persisted but fails at fire-time with the unhelpful\n\t// `platform \"\" not found for session \"\"`. Reject it up front so the\n\t// caller (management API, /cron/add, /cron edit) sees an immediate\n\t// 400 instead of a job that silently never runs.\n\tif strings.TrimSpace(j.SessionKey) == \"\" {\n\t\treturn fmt.Errorf(\"session_key is required\")\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 (want default, bypassPermissions, acceptEdits, plan, auto, or dontAsk)\", 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","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/cron.go#L79-L115","documentation":"validateCronJob requires a non-empty SessionKey on every cron job. SessionKey encodes the platform and chat the job runs against; without it the job would be persisted but fail at fire time with an unhelpful 'platform \"\" not found'. The validation makes the failure an immediate, actionable 400 at job creation.","triggerScenarios":"Calling Engine.AddJob (or the /cron/add or /cron edit management API) with a CronJob whose SessionKey field is empty or whitespace-only.","commonSituations":"A client building the job payload omits session_key because it only set the schedule and prompt; an older management-API client predating the field; programmatic job creation that copies a config struct with unset SessionKey; editing a job and accidentally clearing the field.","solutions":["Set session_key to the target conversation's key (format platform:chatID, e.g. \"feishu:oc_abc123\").","If creating via API, include session_key in the JSON body; check the response status is not 400.","When constructing CronJob in Go, populate SessionKey from the active session's key rather than leaving it zero-valued.","Update old automation/clients to send the field; it is now mandatory, not defaulted."],"exampleFix":"// before\ncore.AddJob(core.CronJob{Name: \"nightly\", Schedule: \"0 2 * * *\", Prompt: \"run report\"})\n// after\ncore.AddJob(core.CronJob{Name: \"nightly\", Schedule: \"0 2 * * *\", Prompt: \"run report\",\n    SessionKey: \"feishu:oc_abc123\"})","handlingStrategy":"validation","validationCode":"func validateJobInput(j core.CronJob) error {\n    if strings.TrimSpace(j.SessionKey) == \"\" {\n        return fmt.Errorf(\"session_key is required (platform:chatID)\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := core.AddJob(job); err != nil {\n    if strings.Contains(err.Error(), \"session_key is required\") {\n        http.Error(w, \"session_key is required\", http.StatusBadRequest)\n        return\n    }\n    http.Error(w, err.Error(), http.StatusInternalServerError)\n}","preventionTips":["Always populate session_key from the active conversation (platform:chatID) when building cron jobs","Validate job payloads client-side before POSTing to /cron/add or /cron edit","Never construct CronJob from a partially-filled struct; require SessionKey explicitly at construction","When migrating old job definitions, backfill session_key before re-adding them"],"tags":["cron","validation","required-field","scheduler"],"backgroundTag":"missing-required-argument","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"}