crowdsecurity/crowdsec · error

api register (%s): %w

Error message

api register (%s): %w

What it means

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.

Source

Thrown at pkg/apiclient/client.go:296

	userAgent := config.UserAgent
	if userAgent == "" {
		userAgent = useragent.Default()
	}

	c := &ApiClient{client: client, BaseURL: baseURL, UserAgent: userAgent, URLPrefix: config.VersionPrefix}
	c.common.client = c
	c.Decisions = (*DecisionsService)(&c.common)
	c.Alerts = (*AlertsService)(&c.common)
	c.Auth = (*AuthService)(&c.common)

	resp, err := c.Auth.RegisterWatcher(ctx, models.WatcherRegistrationRequest{MachineID: &config.MachineID, Password: &config.Password, RegistrationToken: config.RegistrationToken})
	if err != nil {
		/*if we have http status, return it*/
		if resp != nil && resp.Response != nil {
			return nil, fmt.Errorf("api register (%s) http %s: %w", c.BaseURL, resp.Response.Status, err)
		}

		return nil, fmt.Errorf("api register (%s): %w", c.BaseURL, err)
	}

	return c, nil
}

func createTransport(url *url.URL) (*http.Transport, *url.URL) {
	urlString := url.String()

	// TCP transport
	if !strings.HasPrefix(urlString, "/") {
		return nil, url
	}

	// Unix transport
	url.Path = "/"
	url.Host = "unix"
	url.Scheme = "http"

View on GitHub (pinned to 909b515798)

Solutions

  1. Confirm the LAPI is listening: 'curl -k <api_url>/health' from the registering host
  2. Fix api_url host/port/scheme (http vs https, unix socket path) in the configuration
  3. If TLS is self-signed, configure the CA cert pool or the client cert as documented instead of raw skipping
  4. Check DNS resolution and firewall rules between the watcher and LAPI hosts

Example fix

// before
return nil, fmt.Errorf("api register (%s): %w", c.BaseURL, err)
// after (caller pre-check)
if err := pingLAPI(ctx, baseURL); err != nil {
    return nil, fmt.Errorf("LAPI unreachable at %s: %w", baseURL, err)
}
return nil, fmt.Errorf("api register (%s): %w", c.BaseURL, err)
Defensive patterns

Strategy: validation

Validate before calling

// verify LAPI reachability before RegisterClient
u, err := url.Parse(config.URL.String())
if err != nil || u.Host == "" {
    return fmt.Errorf("invalid LAPI url %q", config.URL)
}
conn, err := net.DialTimeout("tcp", u.Host, 5*time.Second)
if err != nil {
    return fmt.Errorf("LAPI %s unreachable: %w", u.Host, err)
}
conn.Close()

Type guard

func isTransportError(err error) bool {
    return !errors.Is(err, context.Canceled) &&
        (errors.Is(err, syscall.ECONNREFUSED) ||
         os.IsTimeout(err) ||
         strings.Contains(err.Error(), "connection refused") ||
         strings.Contains(err.Error(), "no such host"))
}

Try / catch

if err != nil {
    if isTransportError(err) {
        // retry with backoff; LAPI may be starting
        return retryWithBackoff(ctx, func() error { _, err := apiclient.RegisterClient(ctx, config, nil); return err })
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/c1a8b32692499900. Report an issue: GitHub.