{"record":{"id":"d212c2a9055da100","repo":"dani-garcia/vaultwarden","slug":"failed-to-parse-global-log-level","errorCode":null,"errorMessage":"Failed to parse global log level","messagePattern":"Failed to parse global log level","errorType":"console","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main.rs","lineNumber":248,"sourceCode":"        |   https://github.com/dani-garcia/vaultwarden/discussions or        |\\n\\\n        |   https://vaultwarden.discourse.group/                             |\\n\\\n        | Report suspected bugs/issues in the software itself at:            |\\n\\\n        |   https://github.com/dani-garcia/vaultwarden/issues/new            |\\n\\\n        \\\\--------------------------------------------------------------------/\\n\"\n    );\n}\n\nfn init_logging() -> Result<log::LevelFilter, Error> {\n    let levels = log::LevelFilter::iter().map(|lvl| lvl.as_str().to_lowercase()).collect::<Vec<String>>().join(\"|\");\n    let log_level_rgx_str = format!(\"^({levels})((,[^,=]+=({levels}))*)$\");\n    let log_level_rgx = regex::Regex::new(&log_level_rgx_str)?;\n    let config_str = CONFIG.log_level().to_lowercase();\n\n    let (level, levels_override) = if let Some(caps) = log_level_rgx.captures(&config_str) {\n        let level = caps\n            .get(1)\n            .and_then(|m| log::LevelFilter::from_str(m.as_str()).ok())\n            .ok_or(Error::new(\"Failed to parse global log level\".to_owned(), \"\"))?;\n\n        let levels_override: Vec<(&str, log::LevelFilter)> = caps\n            .get(2)\n            .map(|m| {\n                m.as_str()\n                    .split(',')\n                    .collect::<Vec<&str>>()\n                    .into_iter()\n                    .filter_map(|s| match s.split_once('=') {\n                        Some((log, lvl_str)) => log::LevelFilter::from_str(lvl_str).ok().map(|lvl| (log, lvl)),\n                        _ => None,\n                    })\n                    .collect()\n            })\n            .ok_or(Error::new(\"Failed to parse overrides\".to_owned(), \"\"))?;\n\n        (level, levels_override)\n    } else {","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/dani-garcia/vaultwarden/blob/0cefa4cca7c9f2a5579dd290f78193b543818c51/src/main.rs#L230-L266","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Set LOG_LEVEL to a valid form: LOG_LEVEL=info or LOG_LEVEL=info,vaultwarden::api::icons=debug","Remove surrounding quotes, stray spaces, and empty segments from the env value","Unset LOG_LEVEL to fall back to the default and restart, confirming the rest of the config is fine","If running a custom build, verify every regex token is a string log::LevelFilter::from_str accepts"],"exampleFix":"# before\nLOG_LEVEL=\"Info, vaultwarden::api::icons=Debug \"\n# after\nLOG_LEVEL=info,vaultwarden::api::icons=debug","handlingStrategy":"validation","validationCode":"# Validate LOG_LEVEL before starting the server\npython3 - <<'EOF'\nimport os, re, sys\nlvl = r'off|error|warn|info|debug|trace'\nv = os.environ.get('LOG_LEVEL', 'info').strip().lower()\nif not re.fullmatch(rf'({lvl})((,[^,=]+=({lvl}))*)', v):\n    print('LOG_LEVEL must look like: info,vaultwarden::api::icons=debug')\n    sys.exit(1)\nEOF","typeGuard":"fn is_valid_log_level(s: &str) -> bool {\n    let lvl = r\"off|error|warn|info|debug|trace\";\n    regex::Regex::new(&format!(\"^({lvl})((,[^,=]+=({lvl}))*)$\")).unwrap().is_match(&s.to_lowercase())\n}","tryCatchPattern":null,"preventionTips":["Use only off|error|warn|info|debug|trace as levels","Write overrides as module=level with no spaces","Add a pre-start config lint for LOG_LEVEL in container entrypoints","Lowercase the value in deployment tooling to match the parser"],"tags":["rust","configuration","logging","startup"],"backgroundTag":null,"analyzedSha":"0cefa4cca7c9f2a5579dd290f78193b543818c51","analyzedAt":"2026-08-16T07:44:56.102Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}