{"record":{"id":"e590e0aaf056f740","repo":"chenhg5/cc-connect","slug":"cron-project-not-found","errorCode":null,"errorMessage":"cron project not found","messagePattern":"cron project not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/cron.go","lineNumber":52,"sourceCode":"\tMute        bool      `json:\"mute,omitempty\"`         // suppress ALL messages (start + result); job runs silently\n\tSessionMode string    `json:\"session_mode,omitempty\"` // \"\" or \"reuse\" = share active session; \"new_per_run\" = fresh session each run\n\tMode        string    `json:\"mode,omitempty\"`         // permission mode override for this job; \"\" = use project default\n\tTimeoutMins *int      `json:\"timeout_mins,omitempty\"` // nil = default 30m wait; 0 = no limit; >0 = minutes\n\tCreatedAt   time.Time `json:\"created_at\"`\n\tLastRun     time.Time `json:\"last_run,omitempty\"`\n\tLastError   string    `json:\"last_error,omitempty\"`\n}\n\n// IsShellJob returns true if the job runs a shell command directly.\nfunc (j *CronJob) IsShellJob() bool {\n\treturn j.Exec != \"\"\n}\n\nconst defaultCronJobTimeout = 30 * time.Minute\n\nvar (\n\tErrCronJobNotFound     = errors.New(\"cron job not found\")\n\tErrCronProjectNotFound = errors.New(\"cron project not found\")\n)\n\n// ExecutionTimeout returns how long the scheduler waits for the job goroutine to finish.\n// nil TimeoutMins uses 30 minutes. *TimeoutMins == 0 means wait without a time limit.\n// *TimeoutMins > 0 means that many minutes.\nfunc (j *CronJob) ExecutionTimeout() time.Duration {\n\tif j.TimeoutMins == nil {\n\t\treturn defaultCronJobTimeout\n\t}\n\tif *j.TimeoutMins <= 0 {\n\t\treturn 0\n\t}\n\treturn time.Duration(*j.TimeoutMins) * time.Minute\n}\n\n// UsesNewSessionPerRun reports whether each cron run should use a new engine session\n// instead of reusing the active session for the session_key.\nfunc (j *CronJob) UsesNewSessionPerRun() bool {","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/cron.go#L34-L70","documentation":"ErrCronProjectNotFound is the sentinel error returned by RunJobNow when a job exists but its referenced project is missing — the job's Project name does not resolve to a configured cron project. It is wrapped with the project name and asserted in cron_test.go. Unlike a missing job, the job id itself was valid.","triggerScenarios":"Calling scheduler.RunJobNow for a job whose job.Project names a project that is absent from the scheduler's project set (deleted/renamed project, config edited to drop the project).","commonSituations":"Renaming or removing a project in config.toml while old cron job entries still reference the old name, partial config reload where jobs loaded but projects did not, or hand-editing a job's project field with a typo.","solutions":["Re-add or fix the project name in config so job.Project resolves","Update or delete the orphaned cron job that references the missing project","Use errors.Is(err, ErrCronProjectNotFound) to surface a 404/config-repair message to API clients","Reload config after editing to ensure jobs and projects are consistent"],"exampleFix":"// before\nprojects:\n  - name: \"deploy\"   # job references \"ghost\"\n// after\nprojects:\n  - name: \"deploy\"\n  - name: \"ghost\"    # or update the job to reference \"deploy\"","handlingStrategy":"try-catch","validationCode":"job := scheduler.Store().Get(jobID)\nif job != nil && scheduler.Project(job.Project) == nil {\n    return fmt.Errorf(\"job %q references missing project %q\", jobID, job.Project)\n}","typeGuard":"func isCronProjectNotFound(err error) bool { return errors.Is(err, ErrCronProjectNotFound) }","tryCatchPattern":"if err := scheduler.RunJobNow(jobID); err != nil {\n    if errors.Is(err, ErrCronProjectNotFound) {\n        log.Warn(\"cron job references missing project; fix config\", \"err\", err)\n        return\n    }\n    return err\n}","preventionTips":["Keep cron jobs and their projects in the same config file edited together","After renaming a project, update all jobs referencing it in one change","Use errors.Is against the sentinel rather than parsing the message","Add a startup validation pass that reports jobs whose project is unresolved"],"tags":["cron","scheduler","config","not-found","sentinel-error"],"backgroundTag":"record-not-found","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}