dani-garcia/vaultwarden · error · Error

Failed to parse global log level

Error message

Failed to parse global log level

What it means

init_logging() runs at startup and validates CONFIG.log_level() (LOG_LEVEL env) against a regex assembled from valid level names off|error|warn|info|debug|trace plus optional ',target=level' overrides. After a successful regex match, capture group 1 (the global level) must parse via log::LevelFilter::from_str; this error fires when it does not, aborting startup with a wrapped crate::Error. Because the config string is lowercased first and log's FromStr is case-insensitive, this branch is defensive and effectively unreachable — malformed values almost always fail the regex and get the sibling 'LOG_LEVEL should follow the format...' error instead.

Source

Thrown at src/main.rs:248

        |   https://github.com/dani-garcia/vaultwarden/discussions or        |\n\
        |   https://vaultwarden.discourse.group/                             |\n\
        | Report suspected bugs/issues in the software itself at:            |\n\
        |   https://github.com/dani-garcia/vaultwarden/issues/new            |\n\
        \\--------------------------------------------------------------------/\n"
    );
}

fn init_logging() -> Result<log::LevelFilter, Error> {
    let levels = log::LevelFilter::iter().map(|lvl| lvl.as_str().to_lowercase()).collect::<Vec<String>>().join("|");
    let log_level_rgx_str = format!("^({levels})((,[^,=]+=({levels}))*)$");
    let log_level_rgx = regex::Regex::new(&log_level_rgx_str)?;
    let config_str = CONFIG.log_level().to_lowercase();

    let (level, levels_override) = if let Some(caps) = log_level_rgx.captures(&config_str) {
        let level = caps
            .get(1)
            .and_then(|m| log::LevelFilter::from_str(m.as_str()).ok())
            .ok_or(Error::new("Failed to parse global log level".to_owned(), ""))?;

        let levels_override: Vec<(&str, log::LevelFilter)> = caps
            .get(2)
            .map(|m| {
                m.as_str()
                    .split(',')
                    .collect::<Vec<&str>>()
                    .into_iter()
                    .filter_map(|s| match s.split_once('=') {
                        Some((log, lvl_str)) => log::LevelFilter::from_str(lvl_str).ok().map(|lvl| (log, lvl)),
                        _ => None,
                    })
                    .collect()
            })
            .ok_or(Error::new("Failed to parse overrides".to_owned(), ""))?;

        (level, levels_override)
    } else {

View on GitHub (pinned to 0cefa4cca7)

Solutions

  1. Set LOG_LEVEL to a valid form: LOG_LEVEL=info or LOG_LEVEL=info,vaultwarden::api::icons=debug
  2. Remove surrounding quotes, stray spaces, and empty segments from the env value
  3. Unset LOG_LEVEL to fall back to the default and restart, confirming the rest of the config is fine
  4. If running a custom build, verify every regex token is a string log::LevelFilter::from_str accepts

Example fix

# before
LOG_LEVEL="Info, vaultwarden::api::icons=Debug "
# after
LOG_LEVEL=info,vaultwarden::api::icons=debug
Defensive patterns

Strategy: validation

Validate before calling

# Validate LOG_LEVEL before starting the server
python3 - <<'EOF'
import os, re, sys
lvl = r'off|error|warn|info|debug|trace'
v = os.environ.get('LOG_LEVEL', 'info').strip().lower()
if not re.fullmatch(rf'({lvl})((,[^,=]+=({lvl}))*)', v):
    print('LOG_LEVEL must look like: info,vaultwarden::api::icons=debug')
    sys.exit(1)
EOF

Type guard

fn is_valid_log_level(s: &str) -> bool {
    let lvl = r"off|error|warn|info|debug|trace";
    regex::Regex::new(&format!("^({lvl})((,[^,=]+=({lvl}))*)$")).unwrap().is_match(&s.to_lowercase())
}

Prevention

When it happens

Trigger: A LOG_LEVEL whose first token satisfies the generated regex yet fails LevelFilter::from_str — practically impossible in stock builds since the regex only admits valid level names; realistic only in forks that alter the regex or the level source of truth.

Common situations: Typos in LOG_LEVEL (these usually hit the sibling format error instead); docker-compose values with quotes or trailing whitespace; custom builds that extend the regex with tokens that from_str rejects.

Understand the failure class

Related errors


AI-assisted analysis of dani-garcia/vaultwarden@0cefa4cca7 (2026-08-16). Data as JSON: /api/errors/d212c2a9055da100. Report an issue: GitHub.