chenhg5/cc-connect · error
scheduled_at is required
Error message
scheduled_at is required
What it means
validateTimerJob rejects a TimerJob whose ScheduledAt is the zero time.Time when it is registered via AddJob. Without a schedule time the scheduler cannot compute a firing delay, so such a job is meaningless and is rejected upfront.
Source
Thrown at core/timer.go:65
return defaultTimerJobTimeout
}
if *j.TimeoutMins <= 0 {
return 0
}
return time.Duration(*j.TimeoutMins) * time.Minute
}
// UsesNewSessionPerRun reports whether the timer should use a new engine session.
func (j *TimerJob) UsesNewSessionPerRun() bool {
return NormalizeCronSessionMode(j.SessionMode) == "new_per_run"
}
func validateTimerJob(j *TimerJob) error {
if strings.TrimSpace(j.SessionKey) == "" {
return fmt.Errorf("session_key is required")
}
if j.ScheduledAt.IsZero() {
return fmt.Errorf("scheduled_at is required")
}
if j.Prompt == "" && j.Exec == "" {
return fmt.Errorf("either prompt or exec is required")
}
if j.Prompt != "" && j.Exec != "" {
return fmt.Errorf("prompt and exec are mutually exclusive")
}
mode := NormalizeCronSessionMode(j.SessionMode)
if mode != "" && mode != "new_per_run" {
return fmt.Errorf("invalid session_mode %q (want reuse, new_per_run, or new-per-run)", j.SessionMode)
}
if j.Mode != "" {
switch j.Mode {
case "default", "bypassPermissions", "acceptEdits", "plan", "auto", "dontAsk":
default:
return fmt.Errorf("invalid mode %q", j.Mode)
}
}View on GitHub (pinned to 4000b2338a)
Solutions
- Assign a concrete time to ScheduledAt (e.g. time.Now().Add(5*time.Minute) or a parsed time) before AddJob.
- Check the error return of time.Parse/time.ParseInLocation; on failure the zero time will be stored and rejected.
- If the field comes from JSON, verify the timestamp format is RFC3339-compatible so unmarshaling succeeds.
- Validate ScheduledAt.IsZero() in caller code before AddJob to give a clearer error.
Example fix
// before
when, _ := time.Parse(time.RFC3339, cfg.At) // error swallowed -> zero time
sched.AddJob(&core.TimerJob{SessionKey: k, ScheduledAt: when, Prompt: p})
// after
when, err := time.Parse(time.RFC3339, cfg.At)
if err != nil { return fmt.Errorf("parse scheduled_at: %w", err) }
sched.AddJob(&core.TimerJob{SessionKey: k, ScheduledAt: when, Prompt: p}) Defensive patterns
Strategy: validation
Validate before calling
if job.ScheduledAt.IsZero() { return errors.New("timer job needs scheduled_at") } Prevention
- Never ignore the error from time.Parse — a failed parse yields the zero time
- Default ScheduledAt to time.Now().Add(...) when omitted instead of leaving it zero
- Store timestamps in RFC3339 so unmarshaling round-trips cleanly
When it happens
Trigger: AddJob with a &TimerJob{...} where ScheduledAt was never assigned — e.g. time.Time{} zero value from struct literal, a failed time.Parse whose error was ignored, or an omitted field when deserializing the job.
Common situations: Parsing a user-supplied date string with time.Parse and ignoring the error, leaving ScheduledAt zero; building jobs from config where "scheduled_at" is absent; using `time.Now()` in one package but assigning to the wrong field during a refactor.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- session_key is required
- either prompt or exec is required
- session_key is required
- invalid session_mode %q (want reuse, new_per_run, or new-per
- prompt and exec are mutually exclusive
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/2936bbbbf4014ff4.
Report an issue: GitHub.