crowdsecurity/crowdsec · error

while building request: %w

Error message

while building request: %w

What it means

SignalService.Add builds the POST /signals request via PrepareRequest before sending alert signals to the API; if construction fails (trailing-slash BaseURL violation, URL parse error, JSON marshal failure of the AddSignalsRequest, gzip error), it wraps the error as 'while building request'. Nothing has been sent to the server yet — the failure is entirely client-side.

Source

Thrown at pkg/apiclient/signal.go:19

package apiclient

import (
	"context"
	"fmt"
	"net/http"

	"github.com/crowdsecurity/crowdsec/pkg/modelscapi"
	log "github.com/sirupsen/logrus"
)

type SignalService service

func (s *SignalService) Add(ctx context.Context, signals *modelscapi.AddSignalsRequest) (interface{}, *Response, error) {
	u := fmt.Sprintf("%s/signals", s.client.URLPrefix)

	req, err := s.client.PrepareRequest(ctx, http.MethodPost, u, &signals)
	if err != nil {
		return nil, nil, fmt.Errorf("while building request: %w", err)
	}

	var response interface{}

	resp, err := s.client.Do(ctx, req, &response)
	if err != nil {
		return nil, resp, fmt.Errorf("while performing request: %w", err)
	}

	if resp.Response.StatusCode != http.StatusOK {
		log.Warnf("Signal push response : http %s", resp.Response.Status)
	} else {
		log.Debugf("Signal push response : http %s", resp.Response.Status)
	}

	return &response, resp, nil
}

View on GitHub (pinned to 909b515798)

Solutions

  1. Inspect the wrapped inner error for the concrete cause
  2. Verify BaseURL is absolute and its path ends with '/'
  3. Ensure the AddSignalsRequest payload contains only JSON-serializable values (no NaN/Inf floats, channels, or funcs)
  4. Validate the URLPrefix/version prefix configuration if the endpoint URL fails to parse

Example fix

// before
req, err := s.client.PrepareRequest(ctx, http.MethodPost, u, &signals)
if err != nil {
    return nil, nil, fmt.Errorf("while building request: %w", err)
}
// after (pre-marshal validation)
if err := validateSignalsJSONMarshalable(signals); err != nil {
    return nil, nil, fmt.Errorf("signals payload not serializable: %w", err)
}
req, err := s.client.PrepareRequest(ctx, http.MethodPost, u, &signals)
if err != nil {
    return nil, nil, fmt.Errorf("while building request: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

// before calling SignalService.Add
if !strings.HasSuffix(client.BaseURL.Path, "/") {
    return errors.New("client BaseURL must end with a trailing slash")
}
if _, err := json.Marshal(signals); err != nil {
    return fmt.Errorf("signals payload not serializable: %w", err)
}

Type guard

func canSendSignals(client *apiclient.ApiClient) bool {
    return client != nil && strings.HasSuffix(client.BaseURL.Path, "/")
}

Try / catch

_, _, err := client.Signal.Add(ctx, signals)
if err != nil {
    if strings.Contains(err.Error(), "while building request") {
        // construction-stage failure: validate URL and payload, no retry will help
        return fmt.Errorf("invalid signal request: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: s.client.PrepareRequest(ctx, http.MethodPost, u, &signals) returns an error before any network I/O: BaseURL without trailing slash, invalid URL prefix, or a signals body containing values the JSON encoder cannot marshal (e.g. NaN in a float field, unsupported types).

Common situations: Custom tooling building an ApiClient with a hand-parsed URL missing the trailing slash; ingesting alert data containing non-JSON-serializable values; version prefix/URLPrefix misconfigured so BaseURL.Parse fails.

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/4dfe35111ed51f01. Report an issue: GitHub.