{"record":{"id":"d320dfcf0017cdfc","repo":"crowdsecurity/crowdsec","slug":"api-register-s-http-s-w","errorCode":null,"errorMessage":"api register (%s) http %s: %w","messagePattern":"api register \\((.+?)\\) http (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/apiclient/client.go","lineNumber":293,"sourceCode":"\t\tclient.Transport = transport\n\t}\n\n\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 = \"/\"","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/apiclient/client.go#L275-L311","documentation":"RegisterClient posts a watcher registration to the LAPI; when the server answers with an HTTP error status (the response object is available), the error includes the base URL and HTTP status plus the underlying body error. It distinguishes server-rejected registrations (which have a status) from pure transport failures (handled by the sibling error at line 296).","triggerScenarios":"c.Auth.RegisterWatcher returns err while resp.Response is non-nil: e.g. 409/400 because the machine is already registered, 403 for a bad/expired registration token, or 500 from LAPI during POST to /watchers.","commonSituations":"Re-running 'cscli lapi register' against a LAPI where the machine ID already exists; using a registration token that is invalid or revoked; LAPI refusing auto-registration because it was disabled; reverse proxy returning an error page.","solutions":["If the machine already exists, either use existing credentials ('cscli machines list'/'cscli lapi register' reuse) or delete and re-register the machine","Verify the registration token (yaml flag or env) matches one issued by 'cscli machines add --token' on the LAPI host","Read the HTTP status in the message: 400/409 = duplicate or malformed request, 403 = token/auth rejection, 5xx = LAPI-side failure","Check LAPI server logs for the corresponding registration rejection reason"],"exampleFix":"// before\nresp, err := c.Auth.RegisterWatcher(ctx, models.WatcherRegistrationRequest{MachineID: &config.MachineID, ...})\n// after (caller guards against duplicate registration)\nif machineAlreadyRegistered(config.MachineID) {\n    return nil, fmt.Errorf(\"machine %q already registered; reuse credentials or delete it first\", config.MachineID)\n}\nresp, err := c.Auth.RegisterWatcher(ctx, models.WatcherRegistrationRequest{MachineID: &config.MachineID, ...})","handlingStrategy":"validation","validationCode":"// check for an existing registration before re-registering\nmachines, _, err := existingClient.Machines.List(ctx)\nif err == nil {\n    for _, m := range machines {\n        if m.MachineId != nil && *m.MachineId == config.MachineID {\n            return errors.New(\"machine already registered; reuse existing credentials\")\n        }\n    }\n}","typeGuard":"func hasHTTPStatus(err error) (string, bool) {\n    var apiErr *apiclient.APIError\n    if errors.As(err, &apiErr) {\n        return apiErr.Status, true\n    }\n    return \"\", false\n}","tryCatchPattern":"_, err := apiclient.RegisterClient(ctx, config, nil)\nif err != nil {\n    var apiErr *apiclient.APIError\n    if errors.As(err, &apiErr) && (apiErr.StatusCode == 409 || apiErr.StatusCode == 400) {\n        // machine already registered: fetch/reuse credentials instead of failing\n    }\n    return err\n}","preventionTips":["Don't re-run 'cscli lapi register' blindly; check existing machines first","Generate registration tokens with 'cscli machines add --token' and use them before expiry","Read the HTTP status embedded in the message before debugging further","Keep registration automated in one idempotent provisioning step"],"tags":["lapi","registration","http"],"backgroundTag":"http-error-response","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"}