crowdsecurity/crowdsec · error

blocklist URL is nil

Error message

blocklist URL is nil

What it means

GetDecisionsFromBlocklist fetches community-blocklist content from a BlocklistLink; the URL to fetch lives in blocklist.URL. If the URL pointer is nil the blocklist entry has no source address, and fetching is impossible, so the function returns this error early.

Source

Thrown at pkg/apiclient/decisions_service.go:177

			partialDecisions[idx] = &models.Decision{
				Scenario: &scenarioDeleted,
				Scope:    decisionsGroup.Scope,
				Type:     new(types.DecisionTypeBan),
				Value:    &decision,
				Duration: &durationDeleted,
				Origin:   new(types.CAPIOrigin),
			}
		}

		v2Decisions.Deleted = append(v2Decisions.Deleted, partialDecisions...)
	}

	return &v2Decisions, resp, nil
}

func (*DecisionsService) GetDecisionsFromBlocklist(ctx context.Context, blocklist *modelscapi.BlocklistLink, lastPullTimestamp string) ([]*models.Decision, bool, error) {
	if blocklist.URL == nil {
		return nil, false, errors.New("blocklist URL is nil")
	}

	log.Debugf("Fetching blocklist %s", *blocklist.URL)

	client := http.Client{}

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, *blocklist.URL, http.NoBody)
	if err != nil {
		return nil, false, err
	}

	if lastPullTimestamp != "" {
		req.Header.Set("If-Modified-Since", lastPullTimestamp)
	}

	log.Debugf("[URL] %s %s", req.Method, req.URL)

	// we don't use client_http Do method because we need the reader and is not provided.

View on GitHub (pinned to 909b515798)

Solutions

  1. Skip blocklists with nil URL before calling: if bl.URL != nil { ... }
  2. Update crowdsec so the CAPI client parses the blocklist metadata correctly and filters null-URL entries.
  3. Log and continue on this error for individual blocklists instead of aborting the whole pull.

Example fix

// before
for _, bl := range blocklists {
    decisions, changed, err := svc.GetDecisionsFromBlocklist(ctx, bl, lastPull)
// after
for _, bl := range blocklists {
    if bl.URL == nil {
        log.Warnf("blocklist %s has no URL, skipping", bl.Name)
        continue
    }
    decisions, changed, err := svc.GetDecisionsFromBlocklist(ctx, bl, lastPull)
Defensive patterns

Strategy: validation

Validate before calling

if blocklist == nil || blocklist.URL == nil || *blocklist.URL == "" {
    return nil // skip
}

Type guard

func hasURL(b *modelscapi.BlocklistLink) bool {
    return b != nil && b.URL != nil && *b.URL != ""
}

Try / catch

decisions, changed, err := svc.GetDecisionsFromBlocklist(ctx, bl, ts)
if err != nil {
    log.Warnf("blocklist fetch failed: %v", err)
    continue
}

Prevention

When it happens

Trigger: Calling GetDecisionsFromBlocklist with a BlocklistLink parsed from CAPI metadata whose url field was absent/JSON null, or a hand-constructed BlocklistLink without setting URL.

Common situations: CAPI returns a blocklist entry with a null url (e.g. malformed or new link type not yet populated), older CAPI response formats, custom code iterating all blocklist links including ones without URLs.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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