{"record":{"id":"de4759578434568f","repo":"crowdsecurity/crowdsec","slug":"local-api-server-stopped-with-error-w","errorCode":null,"errorMessage":"local API server stopped with error: %w","messagePattern":"local API server stopped with error: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/apiserver/apiserver.go","lineNumber":358,"sourceCode":"\t\tHandler:   s.router,\n\t\tTLSConfig: tlsCfg,\n\t\tProtocols: &http.Protocols{},\n\t}\n\n\ts.httpServer.Protocols.SetHTTP1(true)\n\ts.httpServer.Protocols.SetUnencryptedHTTP2(true)\n\ts.httpServer.Protocols.SetHTTP2(true)\n\n\tif s.apic != nil {\n\t\ts.initAPIC(ctx)\n\t}\n\n\ts.httpServerTomb.Go(func() error {\n\t\treturn s.listenAndServeLAPI(ctx, apiReady)\n\t})\n\n\tif err := s.httpServerTomb.Wait(); err != nil {\n\t\treturn fmt.Errorf(\"local API server stopped with error: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// listenAndServeLAPI starts the http server and blocks until it's closed\n// it also updates the URL field with the actual address the server is listening on\n// it's meant to be run in a separate goroutine\nfunc (s *APIServer) listenAndServeLAPI(ctx context.Context, apiReady chan bool) error {\n\tserverError := make(chan error, 2)\n\n\tlistenConfig := &net.ListenConfig{}\n\n\tstartServer := func(listener net.Listener, canTLS bool) {\n\t\tvar err error\n\n\t\tif canTLS && s.cfg.TLS != nil && (s.cfg.TLS.CertFilePath != \"\" || s.cfg.TLS.KeyFilePath != \"\") {\n\t\t\tif s.cfg.TLS.KeyFilePath == \"\" {","sourceCodeStart":340,"sourceCodeEnd":376,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/apiserver/apiserver.go#L340-L376","documentation":"APIServer.Run returns this when the tomb-wrapped listenAndServeLAPI goroutine exits with an error after Wait() — i.e. the local API server crashed or failed while serving. It aggregates failures from the HTTP listener lifecycle (including error 604).","triggerScenarios":"Run called and the internal HTTP server fails: listener creation error, accept loop failure, or shutdown error propagated from listenAndServeLAPI.","commonSituations":"Port already in use, bind permission denied on a privileged port, listener socket closed unexpectedly mid-run.","solutions":["Inspect the wrapped cause — for bind problems it is usually 'address already in use'.","Free the port: find the process with `ss -ltnp | grep <port>` and stop it, or change api.listen_uri.","Binding <1024 without privileges: change to an unprivileged port or grant capabilities.","If transient, restart crowdsec; check journalctl for the full chain."],"exampleFix":"// before\napi:\n  server:\n    listen_uri: 127.0.0.1:8080\n// after\napi:\n  server:\n    listen_uri: 127.0.0.1:8081","handlingStrategy":"try-catch","validationCode":"// before Run, ensure the port is free\nif ln, err := net.Listen(\"tcp\", cfg.ListenURI); err != nil {\n    return fmt.Errorf(\"LAPI address %s unavailable: %w\", cfg.ListenURI, err)\n} else {\n    ln.Close()\n}","typeGuard":null,"tryCatchPattern":"if err := apiServer.Run(ctx, ready); err != nil {\n    log.Errorf(\"LAPI stopped: %v\", err) // inspect wrapped cause\n    // restart with backoff if the cause is transient\n}","preventionTips":["Use a systemd Restart=on-failure policy for crowdsec.","Avoid double-starting crowdsec (systemd + manual run).","Monitor the LAPI port with a health check.","Keep listen_uri on an unprivileged port in containers."],"tags":["http-server","lifecycle","lapi"],"backgroundTag":"address-already-in-use","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}