{"record":{"id":"c1a8b32692499900","repo":"crowdsecurity/crowdsec","slug":"api-register-s-w","errorCode":null,"errorMessage":"api register (%s): %w","messagePattern":"api register \\((.+?)\\): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/apiclient/client.go","lineNumber":296,"sourceCode":"\tuserAgent := config.UserAgent\n\tif userAgent == \"\" {\n\t\tuserAgent = useragent.Default()\n\t}\n\n\tc := &ApiClient{client: client, BaseURL: baseURL, UserAgent: userAgent, URLPrefix: config.VersionPrefix}\n\tc.common.client = c\n\tc.Decisions = (*DecisionsService)(&c.common)\n\tc.Alerts = (*AlertsService)(&c.common)\n\tc.Auth = (*AuthService)(&c.common)\n\n\tresp, err := c.Auth.RegisterWatcher(ctx, models.WatcherRegistrationRequest{MachineID: &config.MachineID, Password: &config.Password, RegistrationToken: config.RegistrationToken})\n\tif err != nil {\n\t\t/*if we have http status, return it*/\n\t\tif resp != nil && resp.Response != nil {\n\t\t\treturn nil, fmt.Errorf(\"api register (%s) http %s: %w\", c.BaseURL, resp.Response.Status, err)\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"api register (%s): %w\", c.BaseURL, err)\n\t}\n\n\treturn c, nil\n}\n\nfunc createTransport(url *url.URL) (*http.Transport, *url.URL) {\n\turlString := url.String()\n\n\t// TCP transport\n\tif !strings.HasPrefix(urlString, \"/\") {\n\t\treturn nil, url\n\t}\n\n\t// Unix transport\n\turl.Path = \"/\"\n\turl.Host = \"unix\"\n\turl.Scheme = \"http\"\n","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/apiclient/client.go#L278-L314","documentation":"RegisterClient wraps any registration failure that did NOT come with an HTTP response object. This means the request never got a server answer: transport-level failure such as DNS failure, connection refused, timeout, or TLS handshake error. The base URL is included to point at the unreachable target.","triggerScenarios":"c.Auth.RegisterWatcher returns err with resp == nil (or resp.Response == nil): the LAPI host is down, the URL is wrong, the port is closed, DNS fails, TLS cert is untrusted, or the context was canceled mid-request.","commonSituations":"lapi configured on wrong host/port; LAPI service not started; firewall blocking the connection; self-signed cert without proper CA setup (tls rejection); unix socket path wrong; network outage.","solutions":["Confirm the LAPI is listening: 'curl -k <api_url>/health' from the registering host","Fix api_url host/port/scheme (http vs https, unix socket path) in the configuration","If TLS is self-signed, configure the CA cert pool or the client cert as documented instead of raw skipping","Check DNS resolution and firewall rules between the watcher and LAPI hosts"],"exampleFix":"// before\nreturn nil, fmt.Errorf(\"api register (%s): %w\", c.BaseURL, err)\n// after (caller pre-check)\nif err := pingLAPI(ctx, baseURL); err != nil {\n    return nil, fmt.Errorf(\"LAPI unreachable at %s: %w\", baseURL, err)\n}\nreturn nil, fmt.Errorf(\"api register (%s): %w\", c.BaseURL, err)","handlingStrategy":"validation","validationCode":"// verify LAPI reachability before RegisterClient\nu, err := url.Parse(config.URL.String())\nif err != nil || u.Host == \"\" {\n    return fmt.Errorf(\"invalid LAPI url %q\", config.URL)\n}\nconn, err := net.DialTimeout(\"tcp\", u.Host, 5*time.Second)\nif err != nil {\n    return fmt.Errorf(\"LAPI %s unreachable: %w\", u.Host, err)\n}\nconn.Close()","typeGuard":"func isTransportError(err error) bool {\n    return !errors.Is(err, context.Canceled) &&\n        (errors.Is(err, syscall.ECONNREFUSED) ||\n         os.IsTimeout(err) ||\n         strings.Contains(err.Error(), \"connection refused\") ||\n         strings.Contains(err.Error(), \"no such host\"))\n}","tryCatchPattern":"if err != nil {\n    if isTransportError(err) {\n        // retry with backoff; LAPI may be starting\n        return retryWithBackoff(ctx, func() error { _, err := apiclient.RegisterClient(ctx, config, nil); return err })\n    }\n    return err\n}","preventionTips":["Confirm lapi host/port/scheme in config with a curl health check","Start LAPI before provisioning watchers","Configure CA/cert material for self-signed TLS at setup time","Add a startup retry loop for transient network conditions"],"tags":["network","lapi","registration"],"backgroundTag":"connection-refused","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"}