crowdsecurity/crowdsec · error

failed to create request: %w

Error message

failed to create request: %w

What it means

GetPermissions queries the PAPI /permissions endpoint to check the console's subscription plan and permission categories. This error is returned when http.NewRequestWithContext fails to build the GET request — essentially only from an invalid URL composition (p.URL + PAPIVersion + PAPIPermissionsURL) such as a control character or unparseable scheme/host. The permission check aborts and no HTTP call is attempted.

Source

Thrown at pkg/apiserver/papi.go:169

	metrics.PapiOrdersReceived.WithLabelValues(message.Header.OperationType, message.Header.OperationCmd).Inc()

	logger.Debugf("Calling operation '%s'", message.Header.OperationType)

	err := operationFunc(ctx, message, p, sync)
	if err != nil {
		return fmt.Errorf("'%s %s failed: %w", message.Header.OperationType, message.Header.OperationCmd, err)
	}

	return nil
}

func (p *Papi) GetPermissions(ctx context.Context) (PapiPermCheckSuccess, error) {
	httpClient := p.apiClient.GetClient()
	papiCheckURL := fmt.Sprintf("%s%s%s", p.URL, PAPIVersion, PAPIPermissionsURL)

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, papiCheckURL, http.NoBody)
	if err != nil {
		return PapiPermCheckSuccess{}, fmt.Errorf("failed to create request: %w", err)
	}

	resp, err := httpClient.Do(req)
	if err != nil {
		return PapiPermCheckSuccess{}, fmt.Errorf("failed to get response: %w", err)
	}

	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		errResp := PapiPermCheckError{}

		err = json.NewDecoder(resp.Body).Decode(&errResp)
		if err != nil {
			return PapiPermCheckSuccess{}, fmt.Errorf("failed to decode response: %w", err)
		}

		return PapiPermCheckSuccess{}, fmt.Errorf("unable to query PAPI : %s (%d)", errResp.Error, resp.StatusCode)

View on GitHub (pinned to 909b515798)

Solutions

  1. Inspect api.client.papi_url in config.yaml for typos, missing https:// scheme, stray spaces or quotes.
  2. Validate config with `crowdsec -t` after fixing.
  3. Test the composed URL manually: <papi_url>v1/permissions should be syntactically valid in a browser/curl.
  4. If unset, restore the default papi_url (https://api.crowdsec.net/).

Example fix

// before (config.yaml)
api:
  client:
    papi_url: "https://api.crowdsec.net/ "
// after
api:
  client:
    papi_url: https://api.crowdsec.net/
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(papiBaseURL)
if err != nil || u.Scheme == "" || u.Host == "" {
    return fmt.Errorf("invalid papi url %q", papiBaseURL)
}

Try / catch

perms, err := papi.GetPermissions(ctx)
if err != nil {
    if strings.Contains(err.Error(), "failed to create request") {
        // configuration-level URL problem: do not retry, fix config
        return fmt.Errorf("check api.client.papi_url: %w", err)
    }
}

Prevention

When it happens

Trigger: Called at PAPI startup / query flows (QueryPAPIInfo) when p.URL (derived from api.client.papi_url) yields a URL that http.NewRequestWithContext rejects — e.g. missing scheme or invalid characters in the configured papi URL.

Common situations: Hand-edited papi_url in config.yaml with a typo or missing scheme; environment-injected URL with trailing whitespace/newline; copy-paste of the base URL with quotes.

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/332dfca08137b539. Report an issue: GitHub.