chenhg5/cc-connect · error

invalid session_mode %q (want reuse, new_per_run, or new-per

Error message

invalid session_mode %q (want reuse, new_per_run, or new-per-run)

What it means

validateTimerJob normalizes SessionMode via NormalizeCronSessionMode and accepts only "", "reuse", or "new_per_run" (the latter also spelled "new-per-run"). Any other SessionMode string is rejected by AddJob with the offending value quoted.

Source

Thrown at core/timer.go:75

	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)
		}
	}
	if j.TimeoutMins != nil && *j.TimeoutMins < 0 {
		return fmt.Errorf("timeout_mins must be >= 0")
	}
	return nil
}

// TimerStore persists timer jobs to a JSON file.
type TimerStore struct {
	path string
	mu   sync.Mutex

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Use SessionMode: "reuse" to keep using the same session across runs.
  2. Use "new_per_run" (or "new-per-run") to start a fresh session for each run.
  3. Leave SessionMode empty ("") to accept the default behavior.
  4. Call core.NormalizeCronSessionMode on the value first and inspect what it maps to before AddJob.

Example fix

// before
job := &core.TimerJob{SessionKey: k, ScheduledAt: when, Prompt: p, SessionMode: "fresh"}
sched.AddJob(job)
// after
job := &core.TimerJob{SessionKey: k, ScheduledAt: when, Prompt: p, SessionMode: "new_per_run"}
sched.AddJob(job)
Defensive patterns

Strategy: validation

Validate before calling

mode := core.NormalizeCronSessionMode(job.SessionMode)
if mode != "" && mode != "new_per_run" { return fmt.Errorf("bad session_mode %q", job.SessionMode) }

Prevention

When it happens

Trigger: AddJob with TimerJob.SessionMode set to an unrecognized value such as "fresh", "always_new", "NEW_PER_RUN" (if not normalized case-insensitively), or a typo like "new_epr_run".

Common situations: Users guessing mode names in config.toml; configs ported from a different scheduler with different mode vocabulary; case or hyphen/underscore variations of the valid values.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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