gofiber/fiber · warning

service terminate

Error message

service %s terminate: %w

What it means

Collected (not immediately returned) by shutdownServices() when ctx.Err() is non-nil at the top of an iteration. Because shutdown is best-effort, Fiber continues trying to terminate remaining services and appends this wrapped context error to the joined result rather than aborting.

Solutions

  1. Increase the shutdown context deadline via ServicesShutdownContextProvider.
  2. Make each service's Terminate() honor ctx and fail fast rather than blocking.
  3. Order services so dependents terminate before dependencies if the State ordering does not already.
  4. Profile Terminate() latency per service to find the slow one.

Example fix

// before — default background context, no deadline, tight server grace
app.Shutdown()
// a slow Terminate consumes time, later services see canceled ctx

// after — explicit generous shutdown context
app := fiber.New(fiber.Config{
    ServicesShutdownContextProvider: func() context.Context {
        ctx, _ := context.WithTimeout(context.Background(), 30*time.Second)
        return ctx
    },
})
app.Shutdown()
Defensive patterns

Strategy: validation

Validate before calling

// Provide a generous shutdown context sized to total termination cost.
app := fiber.New(fiber.Config{
    ServicesShutdownContextProvider: func() context.Context {
        ctx, _ := context.WithTimeout(context.Background(), 30*time.Second)
        return ctx
    },
})

Try / catch

if err := app.Shutdown(); err != nil {
    var joined interface{ Unwrap() []error }
    if errors.As(err, &joined) {
        for _, e := range joined.Unwrap() {
            if errors.Is(e, context.Canceled) || errors.Is(e, context.DeadlineExceeded) {
                log.Printf("shutdown truncated: %v", e)
            }
        }
    }
}

Prevention

When it happens

Trigger: Shutdown context (from ServicesShutdownContextProvider) is canceled or expired while services are still being terminated. A long-running Terminate() on an earlier service consumed the deadline, leaving none for later ones.

Common situations: Shutdown deadline too tight for the service set; a service blocks in Terminate() (unclosed goroutines, hung network close); SIGTERM grace period shorter than total termination time.

Related errors


AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11). Data as JSON: /api/errors/48358136d5f20aa6. Report an issue: GitHub.

Appendix: 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 a105acad6c)