chenhg5/cc-connect · error

job timed out after %v

Error message

job timed out after %v

What it means

executeJob waits for the agent run to finish via a done channel; when job.ExecutionTimeout() is positive and elapses before completion, the wait is abandoned and err is set to "job timed out after <timeout>". MarkFired stores this error on the job. Timeouts only apply when ExecutionTimeout() > 0 — zero/negative means wait indefinitely.

Source

Thrown at core/timer.go:422

		slog.Error("timer: project not found", "job", jobID, "project", job.Project)
		ts.store.MarkFired(jobID, fmt.Errorf("project %q not found", job.Project))
		return
	}

	slog.Info("timer: executing job", "id", jobID, "project", job.Project, "prompt", truncateStr(job.Prompt, 60))

	done := make(chan error, 1)
	go func() {
		done <- engine.ExecuteTimerJob(job)
	}()

	var err error
	timeout := job.ExecutionTimeout()
	if timeout > 0 {
		select {
		case err = <-done:
		case <-time.After(timeout):
			err = fmt.Errorf("job timed out after %v", timeout)
		}
	} else {
		err = <-done
	}

	ts.store.MarkFired(jobID, err)

	if err != nil {
		slog.Error("timer: job failed", "id", jobID, "error", err)
	} else {
		slog.Info("timer: job completed", "id", jobID)
	}
}

func GenerateTimerID() string {
	b := make([]byte, 4)
	if _, err := rand.Read(b); err != nil {
		panic(fmt.Errorf("generate timer id: %w", err))

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Increase TimeoutMins on the job to comfortably exceed the worst-case run duration.
  2. Set TimeoutMins to 0 (or leave nil per ExecutionTimeout semantics) to disable the timeout for long-running jobs.
  3. Reduce the prompt scope so the run finishes faster; split big tasks into multiple scheduled jobs.
  4. Investigate why the agent hung (permission prompts, stuck tool) — a timeout is masking a blocked session; check job logs for the last activity.

Example fix

// before
to := 2
sched.AddJob(&core.TimerJob{SessionKey: k, ScheduledAt: when, Prompt: "refactor entire module", TimeoutMins: &to})
// after
to := 30
sched.AddJob(&core.TimerJob{SessionKey: k, ScheduledAt: when, Prompt: "refactor entire module", TimeoutMins: &to})
Defensive patterns

Strategy: try-catch

Validate before calling

// budget the timeout against expected work
if job.TimeoutMins != nil && *job.TimeoutMins > 0 && *job.TimeoutMins < expectedMins { warn("timeout likely too small") }

Try / catch

// after AddJob, inspect the recorded outcome
if rec, ok := store.Fired(job.ID); ok && strings.Contains(rec.Error, "timed out") {
    slog.Warn("timer job hit timeout, increasing budget", "id", job.ID)
    sched.AddJob(cloneWithTimeout(job, *job.TimeoutMins*2))
}

Prevention

When it happens

Trigger: A timer job whose prompt triggers a long agent run (big refactor, slow tool) exceeding TimeoutMins; a hung agent process that never sends completion; a timeout configured too aggressively for the workload.

Common situations: timeout_mins set to 1-2 minutes while the prompt legitimately needs 10; agent waiting on a permission prompt nobody is present to approve; network slowdowns making tool calls exceed the budget.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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