quickwit-oss/quickwit · error

regular expression should compile

Error message

regular expression should compile

What it means

as_redacted_str builds a static Regex to strip credentials (user:password@) from database URIs before display/logging. The expect fires only if the hard-coded regex '(?P<before>^.*://.*)(?P<password>:.*@)(?P<after>.*)' fails to compile — a compile-time constant in the source, so it can only fail if the pattern string itself is broken (e.g. by an edit introducing invalid regex syntax).

Source

Thrown at quickwit/quickwit-common/src/uri.rs:146

        Path::new(&self.uri).extension()?.to_str()
    }

    /// Returns the URI as a string slice.
    pub fn as_str(&self) -> &str {
        &self.uri
    }

    /// Returns the protocol of the URI.
    pub fn protocol(&self) -> Protocol {
        self.protocol
    }

    /// Strips sensitive information such as credentials from URI.
    fn as_redacted_str(&self) -> Cow<'_, str> {
        if self.protocol().is_database() {
            static DATABASE_URI_PATTERN: LazyLock<Regex> = LazyLock::new(|| {
                Regex::new("(?P<before>^.*://.*)(?P<password>:.*@)(?P<after>.*)")
                    .expect("regular expression should compile")
            });
            DATABASE_URI_PATTERN.replace(&self.uri, "$before:***redacted***@$after")
        } else {
            Cow::Borrowed(&self.uri)
        }
    }

    pub fn redact(&mut self) {
        self.uri = self.as_redacted_str().into_owned();
    }

    /// Returns the file path of the URI.
    /// Applies only to `file://` and `ram://` URIs.
    pub fn filepath(&self) -> Option<&Path> {
        if self.protocol().is_file_storage() {
            Some(self.path())
        } else {
            None

View on GitHub (pinned to a39730c5cd)

Solutions

  1. Fix the regex literal in uri.rs: validate syntax (the regex crate does not support lookaround/backreferences) and named-group names.
  2. Test the pattern in isolation with Regex::new in a unit test so it fails at test time rather than at runtime.
  3. If you need features the regex crate lacks, switch engines (e.g. fancy-regex) or rewrite the pattern without lookarounds.

Example fix

// before
Regex::new("(?P<before>^.*://.*)(?P<password>:.*@)(?P<after>.*)")
    .expect("regular expression should compile")
// after (validated at test time; keep runtime expect)
Regex::new("(?P<before>^.*?://.*?)(?P<password>:[^@]*@)(?P<after>.*)")
    .expect("regular expression should compile")
Defensive patterns

Strategy: validation

Validate before calling

Regex::new("(?P<before>^.*://.*)(?P<password>:.*@)(?P<after>.*)").expect("regex compiles"); // run in a unit test / build step

Prevention

When it happens

Trigger: Calling Uri::as_redacted_str() (directly or via redact()/Display/fmt) on a database-protocol URI while the embedded DATABASE_URI_PATTERN is invalid. With the shipped pattern this is unreachable; it becomes reachable only when the regex literal in quickwit/quickwit-common/src/uri.rs is modified incorrectly.

Common situations: A developer edits the redaction regex (e.g. adds a look-around unsupported by the regex crate, or a malformed named group) and then any log line or Debug/Display of a postgres/mysql URI triggers the panic at first LazyLock initialization.

Related errors


AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08). Data as JSON: /api/errors/3f1c2f2bf08515e9. Report an issue: GitHub.