slimtoolkit/slim · error
setting read timeout: %v
Error message
setting read timeout: %v
What it means
After dialing the FastCGI backend, RoundTrip applies the transport's ReadTimeout via fcgiBackend.SetReadTimeout. If the connection cannot accept the timeout (typically because the connection is already broken/closed), the error is wrapped as "setting read timeout: %v". The backend conn is usable only if both read and write timeouts apply cleanly.
Source
Thrown at pkg/app/master/probe/http/internal/fastcgi.go:97
network, address := "tcp", r.URL.Host
if log.IsLevelEnabled(log.DebugLevel) {
envJSON, _ := json.Marshal(env)
log.Debugf("HTTP probe - FastCGI env - %s", string(envJSON))
}
ctx := r.Context()
dialer := net.Dialer{Timeout: t.DialTimeout}
fcgiBackend, err := DialWithDialerContext(ctx, network, address, dialer)
if err != nil {
// TODO: wrap in a special error type if the dial failed, so retries can happen if enabled
return nil, fmt.Errorf("dialing backend: %v", err)
}
// fcgiBackend gets closed when response body is closed (see clientCloser)
// read/write timeouts
if err := fcgiBackend.SetReadTimeout(t.ReadTimeout); err != nil {
return nil, fmt.Errorf("setting read timeout: %v", err)
}
if err := fcgiBackend.SetWriteTimeout(t.WriteTimeout); err != nil {
return nil, fmt.Errorf("setting write timeout: %v", err)
}
contentLength := r.ContentLength
if contentLength == 0 {
contentLength, _ = strconv.ParseInt(r.Header.Get("Content-Length"), 10, 64)
}
var resp *http.Response
switch r.Method {
case http.MethodHead:
resp, err = fcgiBackend.Head(env)
case http.MethodGet:
resp, err = fcgiBackend.Get(env, r.Body, contentLength)
case http.MethodOptions:
resp, err = fcgiBackend.Options(env)View on GitHub (pinned to 81940d17fa)
Solutions
- Inspect the wrapped error for an os.ErrDeadlineUnsupported / 'not supported' cause and remove or adjust ReadTimeout if deadlines aren't supported.
- Check the backend for immediate disconnects (php-fpm logs, container restarts).
- Retest connectivity — this often masks a race where the backend died between dial and timeout setup.
- Set a sane positive ReadTimeout (not zero/negative) on the transport.
Example fix
// before
t := FastCGITransport{ DialTimeout: time.Second } // ReadTimeout unset/zero
// after
t := FastCGITransport{ DialTimeout: time.Second, ReadTimeout: 30 * time.Second, WriteTimeout: 30 * time.Second } Defensive patterns
Strategy: retry
Validate before calling
// only fail on genuinely unsupported deadlines
if err := fcgiBackend.SetReadTimeout(t.ReadTimeout); err != nil {
if errors.Is(err, os.ErrDeadlineUnsupported) {
log.Warn("deadlines unsupported on this conn; continuing")
} else {
return err
}
} Try / catch
resp, err := fcgiTransport.RoundTrip(req)
if err != nil && strings.Contains(err.Error(), "setting read timeout") {
if !errors.Is(errors.Unwrap(err), os.ErrDeadlineUnsupported) {
return retryRoundTrip(req) // likely transient conn death
}
} Prevention
- Set explicit positive ReadTimeout/WriteTimeout values on the transport.
- Watch for backends that accept then immediately close (worker crashes) — fix that first.
- Check backend logs for OOM kills or worker exhaustion causing dead connections.
When it happens
Trigger: RoundTrip where SetReadTimeout fails right after a successful dial — usually the underlying conn is dead (peer reset immediately), or the conn type does not support deadline setting (e.g. certain mock/unix conns).
Common situations: Backend accepting then instantly closing the connection (crashing php-fpm worker); DialTimeout succeeding but the conn being torn down before deadlines are set; unusual network stacks where deadlines are unsupported.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- setting write timeout: %v
- fcgi: invalid header version
- building environment: %v
- dialing backend: %v
- start monitor timeout
AI-assisted analysis of slimtoolkit/slim@81940d17fa (2026-08-31).
Data as JSON: /api/errors/ce1742954740bfb4.
Report an issue: GitHub.