stamparm/maltrail · error · ConfigError

missing mandatory option

Error message

missing mandatory option '{option}' in configuration file '{}'

What it means

The sensor's configuration parser requires three mandatory options: MONITOR_INTERFACE, CAPTURE_BUFFER and LOG_DIR. During config load it iterates this list and, if any key is absent from the raw parsed configuration, it bails with this message naming the missing option and the config file path. The library fails fast instead of guessing defaults, since these options have no safe defaults for a monitoring sensor.

Solutions

  1. Open the config file named in the error and add the missing option key shown in the message (e.g. MONITOR_INTERFACE=eth0).
  2. Compare the file against a known-good sample config to spot any other missing mandatory keys (all three are validated in one pass, but the first missing one aborts).
  3. Verify the sensor is reading the intended file: resolve_root may redirect a relative config path; check that you edited the file actually being loaded.
  4. If upgrading from an older sensor version, migrate renamed/removed keys to the current names.

Example fix

// before (config.conf, missing keys)
LOG_DIR=/var/log/sensor

// after (config.conf)
MONITOR_INTERFACE=eth0
CAPTURE_BUFFER=128
LOG_DIR=/var/log/sensor
Defensive patterns

Strategy: validation

Validate before calling

const MANDATORY: &[&str] = &["MONITOR_INTERFACE", "CAPTURE_BUFFER", "LOG_DIR"];
let raw = parse_raw(&content, &root)?;
let missing: Vec<_> = MANDATORY.iter().filter(|k| !raw.contains_key(**k)).collect();
if !missing.is_empty() {
    return Err(format!("config file {} missing: {}", config_file.display(), missing.join(", ")));
}

Prevention

When it happens

Trigger: Loading a sensor config file (parse_raw path in sensor/src/config.rs) that lacks any of the keys MONITOR_INTERFACE, CAPTURE_BUFFER, or LOG_DIR. Occurs when the config file is truncated, hand-edited and a section was deleted, or a new install was never fully populated.

Common situations: Fresh deployment with a minimal/incomplete config; config copied from an older sensor version where an option was named differently; a line was commented out while debugging; file was overwritten by a template missing these keys.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of stamparm/maltrail@77cfb06d76 (2026-09-13). Data as JSON: /api/errors/67de444b11709cd8. Report an issue: GitHub.

Appendix: source

Thrown at sensor/src/config.rs:745

        _ => false,
    }
}

impl Config {
    pub fn load(config_file: &Path) -> Result<Config, ConfigError> {
        if !config_file.is_file() {
            bail!("missing configuration file '{}'", config_file.display());
        }
        crate::cprintln!("[i] using configuration file '{}'", config_file.display());
        let content = std::fs::read_to_string(config_file)
            .map_err(|e| ConfigError(format!("unable to read configuration file '{}' ({e})", config_file.display())))?;

        let root = settings::resolve_root(config_file);
        let raw = parse_raw(&content, &root)?;

        for option in ["MONITOR_INTERFACE", "CAPTURE_BUFFER", "LOG_DIR"] {
            if !raw.contains_key(option) {
                bail!("missing mandatory option '{option}' in configuration file '{}'", config_file.display());
            }
        }

        for name in unknown_keys(&raw) {
            // A typo'd name parses fine and is then ignored - the feature it was meant to
            // configure just stays off while the file looks correct. Warn rather than fail: an
            // older config meeting a newer sensor (or the reverse) must keep working.
            crate::cprintln!(
                "[!] unknown configuration option '{}' in configuration file '{}' (typo? see 'maltrail.conf' for the accepted names)",
                name,
                config_file.display()
            );
        }

        let capture_buffer_raw = get_str(&raw, "CAPTURE_BUFFER");
        let capture_buffer = if capture_buffer_raw.is_empty() {
            0
        } else {

View on GitHub (pinned to 77cfb06d76)