stamparm/maltrail · error · ConfigError

invalid USERS entry ' ' [?] (hint: add whitespace at start…

Error message

invalid USERS entry '{line}'
[?] (hint: add whitespace at start of line)

What it means

The sensor's config parser (parse_raw) rejects a whitespace-less line inside a USERS array that contains characters other than alphanumerics or underscore. Because USERS entries like admin: secret would contain ':' with no space separator, this is almost certainly a malformed USERS block — and the parser helpfully suggests the likely cause: the line is missing its leading whitespace, so it isn't being treated as an array entry at all.

Solutions

  1. Indent the USERS entry so the parser treats it as an array element (add whitespace at the start of the line)
  2. Ensure each entry has the expected separator with spacing (e.g. `admin secret`) rather than flush-left `admin:secret`
  3. Check the line directly above: an unindented line ends the current array context
  4. Re-run the sensor after fixing; the same check covers other arrays with the generic message

Example fix

// before (config)
USERS
admin: secret
// after
USERS
    admin secret
Defensive patterns

Strategy: validation

Validate before calling

import re
for i, line in enumerate(open("sensor.conf")):
    stripped = line.rstrip("\n")
    if 'USERS' in stripped or (stripped and not stripped[0].isspace()):
        continue
    if stripped.strip() and not re.fullmatch(r'[A-Za-z0-9_ ]+', stripped.strip()):
        print(f"check line {i+1}: {stripped!r}")

Prevention

When it happens

Trigger: Loading the sensor config when a line under [USERS]-style array context has no space, contains non-[A-Za-z0-9_] characters (like ':' in user:pass), and the current array being parsed is USERS — typically the entry lost its indentation.

Common situations: Writing `admin: secret` flush-left inside a USERS block instead of indented; copy-pasting entries from docs without indentation; converting an old config format where entries had different syntax.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at sensor/src/config.rs:441

        // re.sub(r"\s*#.*", "", line)
        let line = match line.find('#') {
            Some(idx) => {
                let mut cut = idx;
                while cut > 0 && line.as_bytes()[cut - 1].is_ascii_whitespace() {
                    cut -= 1;
                }
                &line[..cut]
            }
            None => line,
        };
        if line.trim().is_empty() {
            continue;
        }

        if !line.contains(' ') {
            if line.bytes().any(|c| !(c.is_ascii_alphanumeric() || c == b'_')) {
                if array.as_deref() == Some("USERS") {
                    bail!("invalid USERS entry '{line}'\n[?] (hint: add whitespace at start of line)");
                }
                bail!("invalid configuration (line: '{line}')");
            }
            let name = line.to_ascii_uppercase();
            out.insert(name.clone(), Value::Array(Vec::new()));
            array = Some(name);
            continue;
        }

        if let Some(arr) = array.clone() {
            if line.starts_with(' ') {
                let entry = line.trim().to_string();
                if let Some(Value::Array(items)) = out.get_mut(&arr) {
                    // IP_ALIASES is a server-side option, parsed here only so the sensor does
                    // not reject a shared configuration file. Its address part is not expanded.
                    items.push(entry);
                }
                continue;

View on GitHub (pinned to 77cfb06d76)