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

  1. Assign a concrete time to ScheduledAt (e.g. time.Now().Add(5*time.Minute) or a parsed time) before AddJob.
  2. Check the error return of time.Parse/time.ParseInLocation; on failure the zero time will be stored and rejected.
  3. If the field comes from JSON, verify the timestamp format is RFC3339-compatible so unmarshaling succeeds.
  4. 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

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


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/2936bbbbf4014ff4. Report an issue: GitHub.