stamparm/maltrail · error

aho-corasick build

Error message

aho-corasick build

What it means

The settings module builds Aho-Corasick automata for pre-condition pattern matching via ac(), which panics with "aho-corasick build" if AhoCorasick::new(patterns) returns an Err. The aho-corasick library only fails construction in rare cases (e.g. the match kind or pattern set is not representable, or pattern limits are exceeded), so this expect is an internal-invariant assertion: Statics::build cannot proceed without the automaton.

Solutions

  1. Inspect the pattern constants passed to ac() (SUSPICIOUS_HTTP_REQUEST_PRE_CONDITION etc.) for entries incompatible with the builder configuration
  2. Print/return the underlying aho_corasick::Error instead of expect to see the real cause
  3. Pin or update the aho-corasick dependency to a version compatible with the pattern set
  4. If an empty pattern list is legitimate, construct with AhoCorasickBuilder and handle the empty case explicitly

Example fix

// before
fn ac(patterns: &[&str]) -> AhoCorasick {
    AhoCorasick::new(patterns).expect("aho-corasick build")
}
// after
fn ac(patterns: &[&str]) -> AhoCorasick {
    AhoCorasick::new(patterns).unwrap_or_else(|e| panic!("aho-corasick build failed for {:?}: {e}", patterns))
}
Defensive patterns

Strategy: validation

Validate before calling

assert!(!patterns.is_empty(), "ac() pattern list must not be empty");

Type guard

fn valid_patterns(patterns: &[&str]) -> bool { !patterns.is_empty() && patterns.iter().all(|p| !p.is_empty()) }

Try / catch

let automaton = AhoCorasick::new(patterns).unwrap_or_else(|e| panic!("aho-corasick build: {e}"));

Prevention

When it happens

Trigger: Statics::build() calls ac(SUSPICIOUS_HTTP_REQUEST_PRE_CONDITION), ac(SUSPICIOUS_PROXY_PROBE_PRE_CONDITION), ac(WHITELIST_HTTP_REQUEST_PATHS) or ac(WHITELIST_DIRECT_DOWNLOAD_KEYWORDS) and AhoCorasick::new returns Err (empty/invalid pattern configuration or aho-corasick build limitation for the given MatchKind).

Common situations: Shipping a pattern list constant that is malformed for the builder configuration; upgrading aho-corasick to a version with stricter construction rules; accidentally passing an empty slice where the automaton kind requires patterns.

Related errors


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

Appendix: source

Thrown at sensor/src/settings.rs:243

/// `\A\d+\-\d+\-\d+\-\d+\Z`, hand-coded — the dashed-quad first label check.
#[inline]
pub fn is_dashed_quad(label: &str) -> bool {
    let mut groups = 0;
    for part in label.split('-') {
        if part.is_empty() || !part.bytes().all(|c| c.is_ascii_digit()) {
            return false;
        }
        groups += 1;
    }
    groups == 4
}

pub fn statics() -> &'static Statics {
    STATICS.get().expect("settings::init() must run before statics()")
}

fn ac(patterns: &[&str]) -> AhoCorasick {
    AhoCorasick::new(patterns).expect("aho-corasick build")
}

/// `ac()` for patterns that have to match regardless of case, which is how HTTP header names
/// arrive on the wire.
fn ac_nocase(patterns: &[&str]) -> AhoCorasick {
    aho_corasick::AhoCorasickBuilder::new().ascii_case_insensitive(true).build(patterns).expect("aho-corasick build")
}

impl Statics {
    pub fn build(root: PathBuf) -> Statics {
        let ua_src = build_suspicious_ua_regex(&root);
        let suspicious_ua = match pyre::build(&ua_src) {
            Ok(re) => Some(re),
            Err(e) => {
                crate::ceprintln!("[!] unable to compile SUSPICIOUS_UA_REGEX ({e}); user-agent heuristic disabled");
                None
            }
        };

View on GitHub (pinned to 77cfb06d76)