crowdsecurity/crowdsec · error

source is nil or not an IP

Error message

source is nil or not an IP

What it means

GeoIPEnrichSource populates a models.Source with ASN/country/coordinates GeoIP data, but only makes sense for IP-scoped sources. It refuses to run when the source pointer is nil or the source's Scope is not types.Ip. This is a defensive guard against enriching non-IP entities (e.g. range or user scopes).

Source

Thrown at pkg/appsec/challenge_alert.go:92

	keys := make([]string, 0, len(m))
	for k := range m {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	meta := make(models.Meta, 0, len(keys))
	for _, k := range keys {
		meta = append(meta, &models.MetaItems0{Key: k, Value: m[k]})
	}

	return meta
}

// GeoIPEnrichSource fills a models.Source (IP scope) with GeoIP data — ASN,
// country, coordinates, range — from the shared exprhelpers GeoIP databases.
func GeoIPEnrichSource(src *models.Source) error {
	if src == nil || src.Scope == nil || *src.Scope != types.Ip {
		return errors.New("source is nil or not an IP")
	}

	asndata, err := exprhelpers.GeoIPASNEnrich(src.IP)
	if err != nil {
		return err
	} else if asndata != nil {
		record := asndata.(*geoip2.ASN)
		src.AsName = record.AutonomousSystemOrganization
		src.AsNumber = fmt.Sprintf("%d", record.AutonomousSystemNumber)
	}

	cityData, err := exprhelpers.GeoIPEnrich(src.IP)
	if err != nil {
		return err
	} else if cityData != nil {
		record := cityData.(*geoip2.City)
		src.Cn = record.Country.IsoCode
		src.Latitude = float32(record.Location.Latitude)

View on GitHub (pinned to 909b515798)

Solutions

  1. Set src.Scope to a pointer to types.Ip before calling GeoIPEnrichSource
  2. Ensure the models.Source is fully constructed (non-nil) before enrichment
  3. Guard the call site: skip GeoIP enrichment when the source scope is not IP

Example fix

// before
src := &models.Source{IP: "1.2.3.4"}
err := GeoIPEnrichSource(src)
// after
ipScope := types.Ip
src := &models.Source{IP: "1.2.3.4", Scope: &ipScope}
err := GeoIPEnrichSource(src)
Defensive patterns

Strategy: validation

Validate before calling

if src == nil || src.Scope == nil || *src.Scope != types.Ip {
    // skip enrichment or construct a proper IP-scoped source
    return nil
}
if err := GeoIPEnrichSource(src); err != nil { ... }

Type guard

func isIPSource(src *models.Source) bool {
    return src != nil && src.Scope != nil && *src.Scope == types.Ip
}

Try / catch

if err := GeoIPEnrichSource(src); err != nil {
    log.Warnf("geoip enrichment skipped: %s", err)
}

Prevention

When it happens

Trigger: Calling GeoIPEnrichSource(src) with src == nil; or with a *models.Source whose Scope is nil; or whose *Scope is anything other than types.Ip (e.g. 'range'). Reached via AppsecEventGeneration or buildChallengeAlert when the appsec event carries a malformed/absent source.

Common situations: Custom appsec code paths building a models.Source by hand and forgetting to set Scope to Ip; a parser/evaluator emitting a challenge alert for an event that never had an IP source; refactors that changed the Source struct and left Scope unset.

Related errors


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