linera-io/linera-protocol · error

Failed to open log file for writing

Error message

Failed to open log file for writing

What it means

Panic during tracing initialization: `open_log_file` reads `LINERA_LOG_DIR`, joins `log_name` with a `.log` extension, and opens the result with append+create. `create(true)` only creates the file itself, never missing parent directories, so a nonexistent or unwritable LINERA_LOG_DIR (or a path that resolves to a directory) makes `open` fail and `.expect` aborts the whole process at startup. The function returns None (file logging silently disabled) only when the env var is unset.

Source

Thrown at linera-service/src/tracing/mod.rs:141

}

/// Opens a log file for writing.
///
/// The location of the file is determined by the `LINERA_LOG_DIR` environment variable,
/// and its name by the `log_name` parameter.
///
/// Returns [`None`] if the `LINERA_LOG_DIR` environment variable is not set.
pub(crate) fn open_log_file(log_name: &str) -> Option<File> {
    let log_directory = env::var_os("LINERA_LOG_DIR")?;
    let mut log_file_path = Path::new(&log_directory).join(log_name);
    log_file_path.set_extension("log");

    Some(
        OpenOptions::new()
            .append(true)
            .create(true)
            .open(log_file_path)
            .expect("Failed to open log file for writing"),
    )
}

#[cfg(not(target_arch = "wasm32"))]
struct WithTraceContext;

#[cfg(not(target_arch = "wasm32"))]
impl<S, N> FormatEvent<S, N> for WithTraceContext
where
    S: Subscriber + for<'span> LookupSpan<'span>,
    N: for<'writer> FormatFields<'writer> + 'static,
{
    fn format_event(
        &self,
        ctx: &fmt::FmtContext<'_, S, N>,
        mut writer: fmt::format::Writer<'_>,
        event: &tracing::Event<'_>,
    ) -> std::fmt::Result {

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Pre-create and own the directory as the service user: `mkdir -p "$LINERA_LOG_DIR" && chown $(id -un) "$LINERA_LOG_DIR"` (or add `RuntimeDirectory=linera` to the systemd unit), then restart.
  2. Unset LINERA_LOG_DIR if file logging is not needed — the code then skips the file layer entirely instead of panicking.
  3. Verify as the service user: `touch "$LINERA_LOG_DIR/probe.log"`.
  4. In custom builds, downgrade the expect to a warning plus None so logging init can never kill the process.

Example fix

// before
Some(
    OpenOptions::new()
        .append(true)
        .create(true)
        .open(log_file_path)
        .expect("Failed to open log file for writing"),
)
// after
match OpenOptions::new().append(true).create(true).open(&log_file_path) {
    Ok(file) => Some(file),
    Err(err) => {
        eprintln!("warning: cannot open log file {}: {err}; file logging disabled", log_file_path.display());
        None
    }
}
Defensive patterns

Strategy: validation

Validate before calling

if let Some(dir) = std::env::var_os("LINERA_LOG_DIR") {
    std::fs::create_dir_all(&dir)
        .with_context(|| format!("LINERA_LOG_DIR is not creatable: {}", dir.to_string_lossy()))?;
    let probe = std::path::Path::new(&dir).join(".probe");
    std::fs::write(&probe, b"")?;
    std::fs::remove_file(&probe)?;
}

Try / catch

// inside open_log_file, replacing the expect:
match OpenOptions::new().append(true).create(true).open(&log_file_path) {
    Ok(file) => Some(file),
    Err(err) => {
        eprintln!("warning: file logging disabled: cannot open {}: {err}", log_file_path.display());
        None
    }
}

Prevention

When it happens

Trigger: Starting any linera-service binary with LINERA_LOG_DIR set to a directory that does not exist; the directory being owned by another user (EACCES); LINERA_LOG_DIR naming a regular file so the joined `<dir>/<name>.log` cannot be opened; SELinux/AppArmor denying writes to the location.

Common situations: systemd or Docker configs setting LINERA_LOG_DIR=/var/log/linera without RuntimeDirectory= or a pre-created writable volume; running as non-root against root-owned /var/log; setups where the logs volume is no longer mounted after a migration.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/278c3d89f5e6fe0d. Report an issue: GitHub.