chenhg5/cc-connect · error
prompt and exec are mutually exclusive
Error message
prompt and exec are mutually exclusive
What it means
validateTimerJob enforces that Prompt and Exec are mutually exclusive: a timer job either sends a prompt to the agent or runs a shell command, not both. Setting both is ambiguous about intent, so AddJob refuses the job.
Source
Thrown at core/timer.go:71
}
// 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)
}
}
if j.TimeoutMins != nil && *j.TimeoutMins < 0 {
return fmt.Errorf("timeout_mins must be >= 0")
}
return nil
}
View on GitHub (pinned to 4000b2338a)
Solutions
- Remove Exec if the job should send a prompt to the agent.
- Remove Prompt if the job should only run a shell command.
- Wrap the shell work as an instruction inside Prompt if both behaviors are truly needed.
- At config-load time, report which keys conflict so the user can delete one.
Example fix
// before
job := &core.TimerJob{SessionKey: k, ScheduledAt: when,
Prompt: "deploy staging", Exec: "./deploy.sh"}
sched.AddJob(job) // mutually exclusive
// after
job := &core.TimerJob{SessionKey: k, ScheduledAt: when, Exec: "./deploy.sh"}
sched.AddJob(job) Defensive patterns
Strategy: validation
Validate before calling
if job.Prompt != "" && job.Exec != "" { return errors.New("set only one of prompt or exec") } Prevention
- Decide the job kind (agent-prompt vs shell-exec) once and populate only that field
- Strip conflicting keys when migrating old configs into the Exec-capable schema
- Document that exec overrides/disallows prompt in config examples
When it happens
Trigger: AddJob with a TimerJob where both Prompt != "" and Exec != "" — e.g. a config entry containing both `prompt` and `exec` keys, or builder code that assigns defaults to both fields.
Common situations: Users copying a timer template that included exec and then adding a prompt; programmatic construction that sets a default Exec and a caller-supplied Prompt; schema drift after adding the Exec feature to existing prompt-based configs.
Related errors
- session_key is required
- scheduled_at is required
- either prompt or exec is required
- invalid session_mode %q (want reuse, new_per_run, or new-per
- invalid mode %q
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/253d6d7fc65d5a20.
Report an issue: GitHub.