dbt-labs/dbt-core · info

[^0-9a-zA-Z_]+

Error message

[^0-9a-zA-Z_]+

What it means

A panic from `Regex::new(r"[^0-9a-zA-Z_]+").expect("valid regex")` — a compile-time-constant regex used to sanitize test-name segments (`CLEAN_REGEX`, replacing every character that is not alphanumeric or underscore). Because the pattern is a hardcoded literal that is syntactically valid, this expect can only fire if the regex engine itself fails to compile a known-good pattern (e.g. engine bug, memory exhaustion at first use, or the constant was edited to an invalid pattern).

Source

Thrown at crates/dbt-parser/src/resolve/resolve_tests/persist_generic_data_tests.rs:1131

    let embedded_cfg = match kwargs.get("config") {
        Some(Value::Object(obj)) => {
            serde_json::from_value(Value::Object(obj.clone())).map_err(|e| {
                fs_err!(
                    ErrorCode::DbtYamlValidationError,
                    "Failed to convert embedded config: {}",
                    e
                )
            })?
        }
        _ => dbt_yaml::Value::Mapping(dbt_yaml::Mapping::new(), Span::default()),
    };

    Ok(merge_yaml_values(passed_in_cfg, embedded_cfg))
}

static CLEAN_REGEX: LazyLock<Regex> =
    LazyLock::new(|| Regex::new(r"[^0-9a-zA-Z_]+").expect("valid regex"));

/// Narrow sanitizer for the test-name segments that become a filename
/// (`source_name` / `resource_name`). The synthesized name is used directly
/// as `target/generic_tests/<name>.sql`, so only path separators must be
/// rewritten — anything else is left alone to avoid changing test names /
/// `unique_id`s for inputs that already worked (e.g. `prod.events`,
/// `my-source`).
static PATH_UNSAFE_REGEX: LazyLock<Regex> =
    LazyLock::new(|| Regex::new(r"[/\\]").expect("valid regex"));

/// Generates a unique hash for a generic test based on uncleaned kwargs.
/// This matches mantle's behavior where the unique_id includes a hash of the
/// test metadata (namespace, name, kwargs) WITHOUT cleaning, ensuring that
/// tests with different expressions (e.g., '> 0' vs '= 0') get different
/// unique_ids even if their cleaned names would be identical.
///
/// https://github.com/dbt-labs/dbt-core/blob/2ef17b836e39d1b4c7a55f14b448a2254378302e/core/dbt/parser/schema_generic_tests.py#L104-L117
fn generate_test_unique_id_hash(

View on GitHub (pinned to 0267ce9170)

Solutions

  1. If the constant was modified, restore a valid pattern such as `[^0-9a-zA-Z_]+` (or fix the syntax error)
  2. Run `cargo build`/tests — regex compilation errors in static patterns are usually caught by tests exercising generic-test name sanitization
  3. If it reproduces with the stock pattern, check the regex crate version for regressions and pin/upgrade accordingly

Example fix

// before (edited, invalid)
static CLEAN_REGEX: LazyLock<Regex> =
    LazyLock::new(|| Regex::new(r"[^0-9a-zA-Z_" ).expect("valid regex"));

// after
static CLEAN_REGEX: LazyLock<Regex> =
    LazyLock::new(|| Regex::new(r"[^0-9a-zA-Z_]+").expect("valid regex"));
Defensive patterns

Strategy: try-catch

Try / catch

// wrap parser invocation; this panic is not user-recoverable, but catch at a boundary
let result = std::panic::catch_unwind(|| run_parse(...));
if result.is_err() {
    eprintln!("parser panicked compiling internal regex; check regex crate build/version");
}

Prevention

When it happens

Trigger: Practically never from user input — the pattern is static. It can only trigger on first use of `CLEAN_REGEX` if the regex crate fails to compile the literal pattern, e.g. due to a runtime fault, a modified build, or someone editing the constant to an invalid expression.

Common situations: A developer edits the constant and introduces a syntax error (e.g. unbalanced `[`), a forked/patched regex crate with broken behavior, or extremely constrained environments where lazy compilation fails.

Related errors


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