# Timeouts

This page explains how a per-task execution limit and its timeout callback behave.

## Setting a Limit

```go
_, err := c.Add("@every 1m", slowJob, "slow job", 3*time.Second, func() {
	log.Println("slow job timed out")
})
if err != nil {
	log.Fatal(err)
}
```

The `time.Duration` argument is the execution limit, not a start delay; the `func()` argument is called only when that limit is exceeded.

## Timeout Behavior

| Behavior | Description |
|---|---|
| Timer start | When the action begins |
| On timeout | Task marked `TaskFailed`; timeout callback invoked |
| Action goroutine | Not interrupted; runs until it returns |
| Panic with a limit set | Not recovered: the action goroutine has no `recover`, so the process exits |
| No limit set | Action runs synchronously until it returns; a panic is recovered and the task is marked `TaskFailed` |
| Timeout error text | `task timeout: <limit in nanoseconds>` for tasks without dependencies, `task timeout <limit in nanoseconds>` for dependent tasks |

See [Configuration](/configuration#task-options) for the full list of `Add` options.
