crowdsecurity/crowdsec · error

failed to create PAPI client: %w

Error message

failed to create PAPI client: %w

What it means

NewPAPI builds the Polling API (PAPI) client by constructing a long-poll HTTP client pointed at the CAPI decisions/stream/poll endpoint. This error wraps any failure from longpollclient.NewLongPollClient (typically URL parsing or HTTP client configuration problems) and aborts PAPI subsystem initialization, so the server cannot receive push-style decision/alert orders from the central API.

Source

Thrown at pkg/apiserver/papi.go:102

	Plan       string   `json:"plan"`
	Categories []string `json:"categories"`
}

func NewPAPI(apic *apic, dbClient *database.Client, consoleConfig *csconfig.ConsoleConfig, logger logging.ExtLogger) (*Papi, error) {
	if logger == nil {
		logger = log.StandardLogger()
	}

	papiURL := *apic.apiClient.PapiURL
	papiURL.Path = fmt.Sprintf("%s%s", PAPIVersion, PAPIPollURL)

	longPollClient, err := longpollclient.NewLongPollClient(longpollclient.LongPollClientConfig{
		Url:        papiURL,
		Logger:     logger,
		HttpClient: apic.apiClient.GetClient(),
	})
	if err != nil {
		return &Papi{}, fmt.Errorf("failed to create PAPI client: %w", err)
	}

	channels := &OperationChannels{
		AddAlertChannel:       apic.AlertsAddChan,
		DeleteDecisionChannel: make(chan []*models.Decision),
	}

	papi := &Papi{
		URL:           apic.apiClient.PapiURL.String(),
		Client:        longPollClient,
		DBClient:      dbClient,
		Channels:      channels,
		SyncInterval:  SyncInterval,
		mu:            sync.Mutex{},
		pullTomb:      tomb.Tomb{},
		syncTomb:      tomb.Tomb{},
		apiClient:     apic.apiClient,
		apic:          apic,

View on GitHub (pinned to 909b515798)

Solutions

  1. Read the wrapped error after 'failed to create PAPI client:' — it names the exact cause (usually URL parse failure).
  2. Check config.yaml: api.client.papi_url must be a valid absolute URL (default https://api.crowdsec.net).
  3. Validate the whole api.client section (url, login, password, ca_cert_path, insecure_skip_verify) with `crowdsec -c config.yaml -t` (config test).
  4. Restore the default papi_url if it was hand-edited, then restart crowdsec.

Example fix

// before (config.yaml)
api:
  client:
    papi_url: api.crowdsec.net/v1   # missing scheme
// after
api:
  client:
    papi_url: https://api.crowdsec.net/
Defensive patterns

Strategy: try-catch

Validate before calling

u, err := url.Parse(cfg.API.Client.PapiURL)
if err != nil || u.Scheme == "" || u.Host == "" {
    return fmt.Errorf("invalid papi_url %q", cfg.API.Client.PapiURL)
}

Try / catch

papi, err := NewPAPI(apic, dbClient, consoleConfig, logger)
if err != nil {
    var urlErr *url.Error
    if errors.As(err, &urlErr) {
        logger.Errorf("PAPI URL misconfigured: %v", urlErr)
    }
    return err
}

Prevention

When it happens

Trigger: Called from NewServer during apiserver startup (and by sync/QueryPAPIInfo) when api.client.papi_url is misconfigured or the underlying http client from apic.apiClient.GetClient() cannot be prepared — e.g. the papi URL fails to parse in NewLongPollClient.

Common situations: Malformed or missing api.client.papi_url in config.yaml; corrupt api section config after manual edits; network proxy/TLS client misconfiguration (insecure_skip_verify/ca_cert path issues) that makes client construction fail at boot.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


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