loco-rs/loco · error

logger initialization failed

Error message

logger initialization failed

What it means

`init_env_filter` builds a `tracing_subscriber::EnvFilter` from the `RUST_LOG` environment variable (with a fallback filter). `EnvFilter::try_new` returns an error when the filter directive string is malformed; the code aggregates failures and `.expect()`s, panicking with 'logger initialization failed' so bad logging configuration fails fast at boot.

Solutions

  1. Fix the `RUST_LOG` value to valid `tracing_subscriber` directive syntax, e.g. `RUST_LOG=info,my_app=debug`
  2. Use a bare level (`error|warn|info|debug|trace`) or `target=level` pairs only; remove stray commas/equals
  3. Unset `RUST_LOG` entirely to fall back to the library's default filter
  4. Validate the filter in staging with `RUST_LOG=... cargo loco doctor` or a quick `EnvFilter::try_new` probe before deploying

Example fix

// before
RUST_LOG=verbose,app=debug=extra
// after
RUST_LOG=info,app=debug
Defensive patterns

Strategy: validation

Validate before calling

// Validate RUST_LOG before initializing
fn valid_filter(v: &str) -> bool {
    v.split(',').all(|d| {
        let d = d.trim();
        d.is_empty()
            || matches!(d, "error"|"warn"|"info"|"debug"|"trace"|"off")
            || d.rsplit_once('=').map_or(!d.is_empty(), |(t, l)| {
                !t.is_empty() && matches!(l, "error"|"warn"|"info"|"debug"|"trace"|"off")
            })
    })
}
if let Ok(v) = std::env::var("RUST_LOG") { assert!(valid_filter(&v), "invalid RUST_LOG: {v}"); }

Try / catch

// Probe the filter in your own code before calling loco's init
match tracing_subscriber::EnvFilter::try_new(std::env::var("RUST_LOG").unwrap_or_default()) {
    Err(e) => eprintln!("bad RUST_LOG: {e}; falling back to info"),
    Ok(_) => { /* safe to init */ }
}

Prevention

When it happens

Trigger: Setting `RUST_LOG` (or the app's configured log level) to a syntactically invalid tracing directive such as `RUST_LOG=trace,foo=bar=baz`, an unknown level like `RUST_LOG=verbose`, or a bad regex in a directive; the try_new call then fails and the expect panics.

Common situations: Copy-pasting log filters from log4j/logback or other frameworks with incompatible syntax; typos in deployment env files; CI pipelines injecting an empty or garbage `RUST_LOG`; a config YAML level field interpolated to something invalid.

Understand the failure class

Background: "is not a valid" / "Invalid ... value" environment variable errors: how libraries validate env vars and what to do when they reject yours — this error's family across 48 libraries.

Related errors


AI-assisted analysis of loco-rs/loco@23639d1e36 (2026-09-12). Data as JSON: /api/errors/bcc813037935d0cc. Report an issue: GitHub.

Appendix: source

Thrown at src/logger.rs:211

    EnvFilter::try_from_default_env()
        .or_else(|_| {
            // user wanted a specific filter, don't care about our internal whitelist
            // or, if no override give them the default whitelisted filter (most common)
            override_filter.map_or_else(
                || {
                    EnvFilter::try_new(
                        MODULE_WHITELIST
                            .iter()
                            .map(|m| format!("{m}={level}"))
                            .chain(std::iter::once(format!("{}={}", H::app_name(), level)))
                            .collect::<Vec<_>>()
                            .join(","),
                    )
                },
                EnvFilter::try_new,
            )
        })
        .expect("logger initialization failed")
}

/// Builds a single boxed tracing [`Layer`] for `make_writer` in the given
/// [`Format`], with ANSI colouring toggled by `ansi` — the same layer [`init`]
/// installs for stdout and the file appender.
///
/// Exposed as a building block so an application overriding
/// [`crate::app::Hooks::init_logger`] can attach Loco's formatted layer to a
/// custom writer (a socket, an in-memory buffer, a second sink) without
/// reimplementing the compact/pretty/json formatting choice.
pub fn init_layer<W2>(
    make_writer: W2,
    format: &Format,
    ansi: bool,
) -> Box<dyn Layer<Registry> + Sync + Send>
where
    W2: for<'writer> MakeWriter<'writer> + Sync + Send + 'static,
{

View on GitHub (pinned to 23639d1e36)