{"id":"f58686f3225baccb","repo":"gofiber/fiber","slug":"service-s-start-w","errorCode":null,"errorMessage":"service %s start: %w","messagePattern":"service (.+?) start: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"services.go","lineNumber":105,"sourceCode":"\tfor idx, srv := range app.configured.Services {\n\t\tif srv == nil {\n\t\t\treturn fmt.Errorf(\"fiber: service at index %d is nil\", idx)\n\t\t}\n\t\tif err := ctx.Err(); err != nil {\n\t\t\t// Context is canceled, return an error the soonest possible, so that\n\t\t\t// the user can see the context cancellation error and act on it.\n\t\t\treturn fmt.Errorf(\"context canceled while starting service %s: %w\", srv.String(), err)\n\t\t}\n\n\t\terr := srv.Start(ctx)\n\t\tif err == nil {\n\t\t\t// mark the service as started\n\t\t\tapp.state.setService(srv)\n\t\t\tcontinue\n\t\t}\n\n\t\tif errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {\n\t\t\treturn fmt.Errorf(\"service %s start: %w\", srv.String(), err)\n\t\t}\n\n\t\terrs = append(errs, fmt.Errorf(\"service %s start: %w\", srv.String(), err))\n\t}\n\treturn errors.Join(errs...)\n}\n\n// shutdownServices Handles the shutdown process of services for the current application.\n// Iterates over all the started services in reverse order and tries to terminate them,\n// returning an error if any error occurs.\nfunc (app *App) shutdownServices(ctx context.Context) error {\n\tif app.state.ServicesLen() == 0 {\n\t\treturn nil\n\t}\n\n\tvar errs []error\n\tfor key, srv := range app.state.Services() {\n\t\tif srv == nil {","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/gofiber/fiber/blob/9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c/services.go#L87-L123","documentation":"Returned by startServices (services.go:105) when a service's Start(ctx) returns context.Canceled or context.DeadlineExceeded. Fiber wraps it so the offending service name (srv.String()) and the original sentinel are visible, and startServices returns immediately rather than continuing to later services.","triggerScenarios":"A Service.Start implementation respects ctx and returns ctx.Err() (or an error wrapping context.Canceled/DeadlineExceeded) when the startup context is canceled. The errors.Is check at services.go:104 classifies it as a context failure and short-circuits the loop.","commonSituations":"Service that blocks on a slow external resource (DB, cache, message broker) under a startup deadline; container orchestrator sends SIGTERM mid-boot; tests with a tight context.WithCancel around app.New.","solutions":["Increase the startup deadline via ServicesStartupContextProvider.","Make Service.Start non-blocking: kick off background reconnect and return nil once ready enough.","Separate the shutdown signal from the startup context so boot is not prematurely canceled.","Use context.WithTimeout with a value sized to your slowest dependency's connect time."],"exampleFix":"// before: Start blocks until deadline\nfunc (s *RedisSvc) Start(ctx context.Context) error {\n    return s.client.Ping(ctx).Err()\n}\n\n// after: bounded retry, return on readiness\nfunc (s *RedisSvc) Start(ctx context.Context) error {\n    return retry.Do(s.client.Ping(ctx).Err,\n        retry.Context(ctx), retry.Attempts(5), retry.Delay(200*time.Millisecond))\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := app.startServices(ctx); err != nil {\n    if errors.Is(err, context.DeadlineExceeded) {\n        // extend deadline and retry, or fail boot with diagnostics\n    }\n}","preventionTips":["Implement Service.Start to be fast or non-blocking.","Use retry-with-backoff inside Start for transient dependency failures.","Monitor boot duration and alert before the deadline."],"tags":["services","context","startup","deadline","cancellation"],"analyzedSha":"9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c","analyzedAt":"2026-08-04T21:44:03.395Z","schemaVersion":2}