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
- Increase TimeoutMins on the job to comfortably exceed the worst-case run duration.
- Set TimeoutMins to 0 (or leave nil per ExecutionTimeout semantics) to disable the timeout for long-running jobs.
- Reduce the prompt scope so the run finishes faster; split big tasks into multiple scheduled jobs.
- 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
- Set TimeoutMins generously above worst-case agent run time
- Watch for permission prompts blocking unattended timer runs — pre-approve or use bypassPermissions
- Monitor MarkFired records for repeated timeout patterns and split oversized prompts
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.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- session_key is required
- scheduled_at is required
- either prompt or exec is required
- missed by %v (stale)
- project %q not found
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/161f359cf2644ea9.
Report an issue: GitHub.