dani-garcia/vaultwarden · error
Failed to parse global log level
Error message
Failed to parse global log level
What it means
init_logging parses the LOG_LEVEL config into a log::LevelFilter via from_str on the regex-captured global part. This error is returned when the captured string is not a valid log level (e.g. 'verbose', 'warn' misspelled, empty).
Solutions
- Set LOG_LEVEL to a valid level: off, error, warn, info, debug, or trace
- Use the override format for module granularity: LOG_LEVEL=info,vaultwarden::api::icons=debug
- Check for typos like 'warning' or 'verbose' in your .env / environment
- Check startup logs to see the exact invalid value echoed in the follow-up format error
Example fix
// before LOG_LEVEL=warning // after LOG_LEVEL=warn
Defensive patterns
Strategy: validation
Validate before calling
const VALID = ['off','error','warn','info','debug','trace'];
const lvl = process.env.LOG_LEVEL?.split(',')[0].trim().toLowerCase();
if (lvl && !VALID.includes(lvl)) throw new Error(`Invalid LOG_LEVEL global level: ${lvl}. Use one of ${VALID.join('/')}`); Type guard
function isValidLogLevel(s) { return ['off','error','warn','info','debug','trace'].includes(s.trim().toLowerCase()); } Prevention
- Only use Rust log crate level names in LOG_LEVEL
- Keep a documented example in .env.template: LOG_LEVEL=info
- Remember 'warning'->warn and 'verbose'->debug do not exist
- Validate env files in CI with a lint script
When it happens
Trigger: LOG_LEVEL set to a value matching the level regex prefix but whose first capture is not one of off/error/warn/info/debug/trace, e.g. LOG_LEVEL='verbose' or LOG_LEVEL='warning'.
Common situations: Users copying levels from other frameworks ('warning' instead of 'warn', 'verbose'); typos; setting LOG_LEVEL to a file path or arbitrary text.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
AI-assisted analysis of dani-garcia/vaultwarden@cc67d644f6 (2026-09-19).
Data as JSON: /api/errors/d212c2a9055da100.
Report an issue: GitHub.
Appendix: source
Thrown at src/main.rs:246
| 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 cc67d644f6)