chenhg5/cc-connect · error

invalid mode %q (want default, bypassPermissions, acceptEdit

Error message

invalid mode %q (want default, bypassPermissions, acceptEdits, plan, auto, or dontAsk)

What it means

validateCronJob restricts the optional Mode (permission mode) field to a fixed allowlist: default, bypassPermissions, acceptEdits, plan, auto, or dontAsk. Any other non-empty string is rejected at job creation so the scheduler never persists a job with an unsupported permission mode.

Source

Thrown at core/cron.go:107

func validateCronJob(j *CronJob) error {
	// SessionKey anchors the cron execution to a platform (ExecuteCronJob
	// derives platformName from the prefix before ":"). Without it the job
	// is persisted but fails at fire-time with the unhelpful
	// `platform "" not found for session ""`. Reject it up front so the
	// caller (management API, /cron/add, /cron edit) sees an immediate
	// 400 instead of a job that silently never runs.
	if strings.TrimSpace(j.SessionKey) == "" {
		return fmt.Errorf("session_key is required")
	}
	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 (want default, bypassPermissions, acceptEdits, plan, auto, or dontAsk)", j.Mode)
		}
	}
	if j.TimeoutMins != nil && *j.TimeoutMins < 0 {
		return fmt.Errorf("timeout_mins must be >= 0")
	}
	return nil
}

// CronStore persists cron jobs to a JSON file.
type CronStore struct {
	path string
	mu   sync.Mutex
	jobs []*CronJob
}

func NewCronStore(dataDir string) (*CronStore, error) {
	dir := filepath.Join(dataDir, "crons")
	if err := os.MkdirAll(dir, 0o755); err != nil {

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Set Mode to one of exactly: "default", "bypassPermissions", "acceptEdits", "plan", "auto", or "dontAsk" — or omit the field for the default.
  2. Fix casing to match the allowlist exactly (e.g. "bypassPermissions", not "BypassPermissions").
  3. Replace legacy mode names from older configs with the current allowlist equivalents.
  4. Constrain the management UI/API client to a fixed enum of the six accepted values.

Example fix

// before
job := core.CronJob{..., Mode: "dangerously-skip-permissions"}
core.AddJob(job) // 400
// after
job := core.CronJob{..., Mode: "bypassPermissions"}
core.AddJob(job)
Defensive patterns

Strategy: validation

Validate before calling

var validModes = []string{"default", "bypassPermissions", "acceptEdits", "plan", "auto", "dontAsk"}
func validateMode(m string) error {
    for _, v := range validModes {
        if m == v { return nil }
    }
    return fmt.Errorf("invalid mode %q", m)
}

Try / catch

if err := validateMode(job.Mode); err != nil {
    http.Error(w, err.Error(), http.StatusBadRequest)
    return
}
if err := core.AddJob(job); err != nil {
    http.Error(w, err.Error(), http.StatusBadRequest)
}

Prevention

When it happens

Trigger: Calling AddJob (or the /cron add / edit endpoints) with Mode set to an unrecognized string such as "safe", "yolo", "normal", "YOLO", or an agent-specific mode not in the allowlist.

Common situations: Users copying mode names from another tool's CLI flags (e.g. "dangerously-skip-permissions"); case mismatches like "DEFAULT" or "AcceptEdits"; older config files carrying modes from previous versions that were renamed; UIs allowing free-text mode entry.

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/c395aa42743a60b4. Report an issue: GitHub.