gofiber/fiber · warning
service %s terminate: %w
Error message
service %s terminate: %w
What it means
Returned by shutdownServices (services.go:128) when the shutdown context is already canceled/deadline-exceeded before a service's Terminate is called. Fiber still attempts best-effort termination of remaining services (it appends the error and continues rather than returning), wrapping ctx.Err() with the service name.
Source
Thrown at services.go:128
return errors.Join(errs...)
}
// shutdownServices Handles the shutdown process of services for the current application.
// Iterates over all the started services in reverse order and tries to terminate them,
// returning an error if any error occurs.
func (app *App) shutdownServices(ctx context.Context) error {
if app.state.ServicesLen() == 0 {
return nil
}
var errs []error
for key, srv := range app.state.Services() {
if srv == nil {
return fmt.Errorf("fiber: service %q is nil", key)
}
if err := ctx.Err(); err != nil {
// Context is canceled, do a best effort to terminate the services.
errs = append(errs, fmt.Errorf("service %s terminate: %w", srv.String(), err))
continue
}
err := srv.Terminate(ctx)
if err != nil {
// Best effort to terminate the services.
errs = append(errs, fmt.Errorf("service %s terminate: %w", srv.String(), err))
continue
}
// Remove the service from the State
app.state.deleteService(srv)
}
return errors.Join(errs...)
}
// logServices logs information about services and returns an error
// if any configured service is nil.View on GitHub (pinned to 9a4c7e57fe)
Solutions
- Give app.Shutdown a generous deadline (e.g. context.WithTimeout(context.Background(), 30*time.Second)).
- Configure ServicesShutdownContextProvider to return a context with adequate remaining time.
- Make Service.Terminate fast and idempotent so it completes within the deadline.
- Avoid double-canceling the shutdown context from signal handlers.
Example fix
// before: tight shutdown deadline
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
_ = app.ShutdownWithContext(ctx)
// after: deadline sized to slowest service drain
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := app.ShutdownWithContext(ctx); err != nil {
log.Printf("shutdown completed with errors: %v", err)
} Defensive patterns
Strategy: validation
Validate before calling
shutdownCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() _ = app.ShutdownWithContext(shutdownCtx)
Try / catch
if err := app.ShutdownWithContext(shutdownCtx); err != nil {
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
log.Printf("shutdown context expired: %v", err)
}
} Prevention
- Use a generous shutdown deadline (longer than max drain time).
- Make Service.Terminate idempotent and fast.
- Avoid double-cancelling the shutdown context from signal handlers.
When it happens
Trigger: Calling app.Shutdown with an already-canceled or short-deadline context, or the shutdown context being canceled mid-loop (e.g. SIGINT during graceful shutdown, or Config.ServicesShutdownContextProvider returning an expired context). The ctx.Err() check at services.go:126 fires.
Common situations: Shutdown deadline shorter than the time needed to drain in-flight requests/close DB pools; double SIGINT forcing immediate cancel; orchestrator hard-killing before graceful drain completes.
Related errors
- context canceled while starting service %s: %w
- service %s start: %w
- memory storage %s: %w
- fiber: service %q is nil
- shutdown: graceful timeout has been reached, exiting
AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04).
Data as JSON: /data/errors/48358136d5f20aa6.json.
Report an issue: GitHub.