crowdsecurity/crowdsec · info

ip not found

Error message

ip not found

What it means

ErrNotFound is returned when the CTI API responds HTTP 404 for the requested IP. GetIPInfo catches it and converts it into a benign empty &SmokeItem{}, so callers usually never see it; it exists to distinguish 'unknown IP' from real errors.

Source

Thrown at pkg/cticlient/client.go:25

	"fmt"
	"io"
	"net/http"
	"strings"

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

const (
	CTIBaseUrl    = "https://cti.api.crowdsec.net/v2"
	smokeEndpoint = "/smoke"
	fireEndpoint  = "/fire"
)

var (
	ErrUnauthorized  = errors.New("unauthorized")
	ErrLimit         = errors.New("request quota exceeded, please reduce your request rate")
	ErrNotFound      = errors.New("ip not found")
	ErrDisabled      = errors.New("cti is disabled")
	ErrUnknown       = errors.New("unknown error")
	defaultUserAgent = useragent.Default()
)

type CrowdsecCTIClient struct {
	httpClient *http.Client
	apiKey     string
	Logger     *log.Entry
	UserAgent  string
}

func (c *CrowdsecCTIClient) doRequest(ctx context.Context, method string, endpoint string, params map[string]string) ([]byte, error) {
	url := CTIBaseUrl + endpoint
	if len(params) > 0 {
		url += "?"
		for k, v := range params {
			url += fmt.Sprintf("%s=%s&", k, v)

View on GitHub (pinned to 909b515798)

Solutions

  1. No fix needed: GetIPInfo already returns an empty SmokeItem for this case
  2. If calling doRequest directly, handle errors.Is(err, ErrNotFound) as an empty result rather than a failure
  3. Validate/skip private and reserved IPs before calling CTI

Example fix

// before
if err != nil { return err }
// after
if errors.Is(err, cticlient.ErrNotFound) {
    return &cticlient.SmokeItem{}, nil
}
Defensive patterns

Strategy: fallback

Validate before calling

// skip private/reserved IPs before querying CTI
if ip := net.ParseIP(s); ip == nil || ip.IsPrivate() || ip.IsLoopback() { return nil }

Type guard

func isPublicIP(s string) bool { ip := net.ParseIP(s); return ip != nil && !ip.IsPrivate() && !ip.IsLoopback() }

Try / catch

resp, err := ctiClient.GetIPInfo(ip)
if errors.Is(err, cticlient.ErrNotFound) {
    resp = &cticlient.SmokeItem{} // empty result, not an error
}

Prevention

When it happens

Trigger: GetIPInfo called with an IP the CTI database has no record of (smokeEndpoint/<ip> returns 404).

Common situations: Looking up private/reserved addresses, fresh IPs never observed by CrowdSec, or IPv6 ranges outside CTI coverage.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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