kataras/iris · error
failed to connect to the server after %d retries
Error message
failed to connect to the server after %d retries
What it means
Application.tryConnect retries connecting to the configured server address up to maxRetries with exponential backoff (base^i seconds); if every attempt fails it returns 'failed to connect to the server after %d retries'. This is surfaced through app.Wait() when a caller waits for a server started asynchronously.
Source
Thrown at iris.go:1197
// Increase the retry interval by the base raised to the power of the number of attempts.
/*
0 2 seconds
1 4 seconds
2 8 seconds
3 ~16 seconds
4 ~32 seconds
5 ~64 seconds
6 ~128 seconds
7 ~256 seconds
8 ~512 seconds
...
*/
retryInterval = time.Duration(math.Pow(base, float64(i+1))) * time.Second
}
}
// All attempts failed, return an error.
return fmt.Errorf("failed to connect to the server after %d retries", maxRetries)
}
// https://ngrok.com/docs
func (app *Application) tryStartTunneling() {
if len(app.config.Tunneling.Tunnels) == 0 {
return
}
app.ConfigureHost(func(su *host.Supervisor) {
su.RegisterOnServe(func(h host.TaskHost) {
publicAddrs, err := tunnel.Start(app.config.Tunneling)
if err != nil {
app.logger.Errorf("Host: tunneling error: %v", err)
return
}
publicAddr := publicAddrs[0]
// to make subdomains resolution still based on this new remote, public addresses.View on GitHub (pinned to 7bedaf55a0)
Solutions
- Check the server actually started: look for earlier errors from app.Run (e.g. 'listen tcp: address already in use').
- Verify the configured address/host matches where the server binds (localhost vs container hostname).
- Increase the retry budget or wait interval if the service legitimately starts slowly.
- Check firewall/security-group rules for the port.
- In containers, use readiness probes / wait-for scripts instead of relying solely on tryConnect retries.
Example fix
// before
app.Run(iris.Addr(":8080"))
go app.Wait()
// after: run and wait in the same flow, or check startup error first
if err := app.Listen(":8080", iris.WithoutStartupLog); err != nil {
log.Fatalf("server failed to start: %v", err)
} Defensive patterns
Strategy: retry
Validate before calling
conn, err := net.DialTimeout("tcp", addr, 2*time.Second)
if err != nil {
log.Printf("target %s not reachable yet: %v", addr, err)
} else { conn.Close() } Try / catch
go app.Run(iris.Addr(addr))
if err := app.Wait(); err != nil {
if strings.Contains(err.Error(), "failed to connect") {
log.Fatalf("server at %s never came up: %v", addr, err) // check server logs for bind errors
}
log.Fatal(err)
} Prevention
- Verify the port is free and the bind address matches the connect address.
- In containers, wait for readiness before connecting.
- Increase retry intervals for slow-starting services.
- Always read the server's own startup errors alongside Wait().
When it happens
Trigger: Calling app.Wait() after app.Run/Spawn in a goroutine while the listener never becomes reachable within maxRetries * exponential intervals — e.g. app.Listen failed, wrong host/port configured, firewall blocking, or the server crashed during startup.
Common situations: Port already in use so the server never starts; connecting to 0.0.0.0/localhost mismatch inside Docker/Kubernetes before the pod is ready; firewalled ports; slow startup exceeding the retry budget (each retry grows as base^(i+1) seconds).
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
Related errors
- multipart related: next part: read: %w
- failed to connect to the server after %d retries
- build: %w
- build: view engine: %v
- build: inject live reload: failed: %v
AI-assisted analysis of kataras/iris@7bedaf55a0 (2026-08-30).
Data as JSON: /api/errors/9760c28597091d17.
Report an issue: GitHub.