netdata/netdata · error

enrichment.network_sources.{source_name}.url must be non-emp

Error message

enrichment.network_sources.{source_name}.url must be non-empty

What it means

Each entry under enrichment.network_sources must declare a non-empty url after trimming. An entry with a missing, blank, or whitespace-only url fails validation at startup. The error names the offending source via the {source_name} interpolation so multi-source configs point at the right block.

Source

Thrown at src/crates/netflow-plugin/src/plugin_config/validation/enrichment.rs:16

use crate::network_sources::compile_jaq_filter;
use crate::plugin_config::{NetworkAttributesValue, PluginConfig, RemoteNetworkSourceTlsConfig};
use anyhow::{Context, Result};
use std::net::SocketAddr;
use std::time::Duration;

pub(super) fn validate_enrichment(cfg: &PluginConfig) -> Result<()> {
    validate_dynamic_routing(cfg)?;

    if cfg.enrichment.classifier_cache_duration < Duration::from_secs(1) {
        anyhow::bail!("enrichment.classifier_cache_duration must be >= 1s");
    }

    for (source_name, source_cfg) in &cfg.enrichment.network_sources {
        if source_cfg.url.trim().is_empty() {
            anyhow::bail!("enrichment.network_sources.{source_name}.url must be non-empty");
        }
        let method = source_cfg.method.trim().to_ascii_uppercase();
        if method != "GET" && method != "POST" {
            anyhow::bail!("enrichment.network_sources.{source_name}.method must be GET or POST");
        }
        if source_cfg.timeout.is_zero() {
            anyhow::bail!("enrichment.network_sources.{source_name}.timeout must be > 0");
        }
        if source_cfg.interval.is_zero() {
            anyhow::bail!("enrichment.network_sources.{source_name}.interval must be > 0");
        }
        validate_network_source_tls(source_name, &source_cfg.tls)?;
        validate_network_source_transform(source_name, &source_cfg.transform)?;
    }

    for (prefix, value) in &cfg.enrichment.networks {
        validate_static_network_attributes(prefix, value)?;
    }

View on GitHub (pinned to 4864de85e2)

Solutions

  1. Set a complete url including scheme, host, and path, e.g., https://api.example.net/v1/prefixes
  2. Verify the key is exactly 'url' — a typo'd key is silently ignored and leaves url empty
  3. Remove the whole source block if the source is not meant to be configured
  4. Check rendered config if generated by templates — the placeholder may not have been substituted

Example fix

# before
enrichment:
  network_sources:
    peers:
      method: GET
      interval: 1h

# after
enrichment:
  network_sources:
    peers:
      url: https://api.example.net/v1/peers
      method: GET
      interval: 1h
Defensive patterns

Strategy: validation

Validate before calling

fn network_source_urls_ok(cfg: &PluginConfig) -> Result<()> {
    for (name, s) in &cfg.enrichment.network_sources {
        anyhow::ensure!(!s.url.trim().is_empty(), "source '{name}' needs a non-empty url");
    }
    Ok(())
}

Prevention

When it happens

Trigger: Declaring enrichment.network_sources.myname with method/interval but no url; url: "" or url: " "; YAML key typo like uri: that silently leaves url unset while the struct default is empty.

Common situations: Copy-pasted source block missing the url line; key renamed by a config refactor; template placeholder never filled in (url: "").

Related errors


AI-assisted analysis of netdata/netdata@4864de85e2 (2026-08-15). Data as JSON: /api/errors/c1eae6e44c2ceb94. Report an issue: GitHub.