dbt-labs/dbt-core · warning

valid regex

Error message

valid regex

What it means

Panic from `Regex::new(...).expect("valid regex")` inside `format_sql_for_display` in crates/dbt-adapter/src/time_machine/validation.rs:441. The function builds a LazyLock regex that inserts newlines before SQL keywords for readable diffs; a panic here means the hard-coded pattern failed to compile. Because it is a compile-time constant pattern, this can only happen if the pattern string is edited incorrectly — it is an internal invariant, not user input.

Source

Thrown at crates/dbt-adapter/src/time_machine/validation.rs:441

    }
}

/// Apply all sanitizers to a SQL string.
fn apply_sanitizers(sql: &str, sanitizers: &[Box<dyn SqlSanitizer>]) -> String {
    let mut result = sql.to_string();
    for sanitizer in sanitizers {
        result = sanitizer.sanitize(&result);
    }
    result
}

// TODO(jason): A real SQL formatter...
/// Format normalized SQL for readable diff display by looking at certain keywords
fn format_sql_for_display(normalized_sql: &str) -> String {
    static RE: LazyLock<Regex> = LazyLock::new(|| {
        Regex::new(
            r"(?i)\b(SELECT|FROM|WHERE|AND|OR|JOIN|LEFT JOIN|RIGHT JOIN|INNER JOIN|OUTER JOIN|CROSS JOIN|ON|GROUP BY|ORDER BY|HAVING|LIMIT|OFFSET|UNION|INTERSECT|EXCEPT|WITH|AS \(|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|COPY GRANTS|VALUES)\b"
        ).expect("valid regex")
    });

    RE.replace_all(normalized_sql, "\n$1").trim().to_string()
}

// ============================================================================
// Deviations
// ============================================================================

/// Deviation for dbt_pov_model_cost_calculator package.
///
/// This package generates dynamic SQL with:
/// - Execution times
/// - Timestamps
/// - Invocation IDs
/// - Run IDs
pub struct DbtPovModelCostCalculatorDeviation;

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Paste the literal pattern into a regex validator (regex101 with Rust flavor) and fix the syntax error at the reported position.
  2. Check parentheses balance in the `(?i)\b(...)\b` group after recent edits.
  3. Escape any literal parentheses or backslashes you intended to match (e.g. the `AS \(` intent).
  4. Convert the expect to a LazyLock built via OnceLock with a fallback plain-string formatter so bad patterns degrade instead of panicking.

Example fix

// before
Regex::new(
    r"(?i)\b(SELECT|FROM|...|AS \(|VALUES)\b"
).expect("valid regex")
// after (verify alternation/group balance)
Regex::new(
    r"(?i)\b(SELECT|FROM|WHERE|AND|OR|JOIN|LEFT JOIN|RIGHT JOIN|INNER JOIN|OUTER JOIN|CROSS JOIN|ON|GROUP BY|ORDER BY|HAVING|LIMIT|OFFSET|UNION|INTERSECT|EXCEPT|WITH|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|COPY GRANTS|VALUES)\b|(?i)\bAS\s*\("
).expect("valid regex")
Defensive patterns

Strategy: try-catch

Validate before calling

fn sql_display_regex_valid() -> bool {
    Regex::new(SQL_DISPLAY_PATTERN).is_ok()
}

Type guard

null

Try / catch

static RE: LazyLock<Option<Regex>> = LazyLock::new(|| {
    Regex::new(SQL_DISPLAY_PATTERN).map_err(|e| { log::error("sql display regex invalid: {e}"); e }).ok()
});
// fall back to plain normalized_sql when RE is None

Prevention

When it happens

Trigger: Editing the static regex literal in format_sql_for_display with an unbalanced group, bad escape (e.g. `\b` typo, stray `\(`), or an unsupported syntax for the `regex` crate version in use; the panic then fires on first use during ValidationMismatch diff formatting or test_format_sql_for_display.

Common situations: Adding a new SQL keyword to the alternation and accidentally breaking the `(?i)\b(...)\b` structure; regex crate upgrade that rejects previously-permissive syntax (e.g. duplicated group names, invalid escapes).

Related errors


AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07). Data as JSON: /api/errors/67df6f3df1d1e794. Report an issue: GitHub.