{"record":{"id":"74f4b8bb6bb6fa04","repo":"chenhg5/cc-connect","slug":"cron-expr-must-be-a-string","errorCode":null,"errorMessage":"cron_expr must be a string","messagePattern":"cron_expr must be a string","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"core/cron.go","lineNumber":544,"sourceCode":"\t\tdelete(cs.entries, id)\n\t}\n\tcs.mu.Unlock()\n\treturn nil\n}\n\n// UpdateJob modifies a field of a cron job and reschedules if necessary.\n// Returns error if job not found, field is read-only, or value is invalid.\nfunc (cs *CronScheduler) UpdateJob(id string, field string, value any) error {\n\tjob := cs.store.Get(id)\n\tif job == nil {\n\t\treturn fmt.Errorf(\"job %q not found\", id)\n\t}\n\n\t// Validate cron expression if updating cron_expr\n\tif field == \"cron_expr\" {\n\t\texpr, ok := value.(string)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"cron_expr must be a string\")\n\t\t}\n\t\tif _, err := cron.ParseStandard(expr); err != nil {\n\t\t\treturn fmt.Errorf(\"invalid cron expression %q: %w\", expr, err)\n\t\t}\n\t}\n\n\t// Validate mode if updating mode field\n\tif field == \"mode\" {\n\t\tif v, ok := value.(string); ok && v != \"\" {\n\t\t\tswitch v {\n\t\t\tcase \"default\", \"bypassPermissions\", \"acceptEdits\", \"plan\", \"auto\", \"dontAsk\":\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"invalid mode %q (want default, bypassPermissions, acceptEdits, plan, auto, or dontAsk)\", v)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Validate session_mode if updating session_mode field","sourceCodeStart":526,"sourceCodeEnd":562,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/cron.go#L526-L562","documentation":"UpdateJob's cron_expr branch requires the new value to be a Go string; a non-string value (JSON number, bool, nested object) is rejected with this error before any parsing. This guards the reflection-based setter which only handles strings.","triggerScenarios":"CronScheduler.UpdateJob(id, \"cron_expr\", value) where value is not a string, e.g. an unmarshaled JSON number 5 or a []any of cron fields.","commonSituations":"API clients sending typed JSON values instead of strings; template engines that render numbers without quotes; test code passing non-string literals.","solutions":["Pass the cron expression as a plain string: UpdateJob(id, \"cron_expr\", \"0 9 * * *\").","If the value comes from JSON, ensure the client sends it quoted, or coerce with fmt.Sprintf only for numeric input.","Coerce any to string at the handler boundary before calling UpdateJob."],"exampleFix":"// before\nsched.UpdateJob(id, \"cron_expr\", 930) // int\n// after\nsched.UpdateJob(id, \"cron_expr\", \"30 9 * * *\")","handlingStrategy":"type-guard","validationCode":"if _, ok := value.(string); !ok { return fmt.Errorf(\"cron_expr must be a string\") }","typeGuard":"func asString(v any) (string, bool) { s, ok := v.(string); return s, ok }","tryCatchPattern":null,"preventionTips":["Ensure JSON clients serialize cron_expr as a quoted string.","Coerce any values to string at the handler boundary.","Add type assertions in tests for all editable fields."],"tags":["go","cron","type-mismatch"],"backgroundTag":"type-mismatch","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"}