EpicGames/lore · critical

Failed to open log file

Error message

Failed to open log file {}

What it means

setup_tracing initializes the tracing subscriber with a pretty log layer writing to a log file passed via CLI args. If std::fs::File::create cannot create/open the log file, the process panics immediately at startup because logging is considered essential. This is a fail-fast design: running without logs would make the chaos client unobservable.

Solutions

  1. Create the parent directory of the log file (e.g. mkdir -p) or correct the --log-file path.
  2. Check write permissions on the target directory and file.
  3. Choose a writable location such as a path under the user's home or temp directory.
  4. In code, handle the io::Error explicitly instead of unwrapping (fall back to stderr-only logging).

Example fix

// before
let log_file_layer = std::fs::File::create(&args.log_file)
    .unwrap_or_else(|_| panic!("Failed to open log file {}", args.log_file));
// after
let log_file_layer = std::fs::File::create(&args.log_file)
    .map_err(|e| anyhow::anyhow!("Failed to open log file {}: {e}", args.log_file))?;
Defensive patterns

Strategy: try-catch

Validate before calling

if let Err(e) = std::fs::metadata(&args.log_file) { /* path may not exist; check parent */ }
if let Some(dir) = std::path::Path::new(&args.log_file).parent() {
    std::fs::create_dir_all(dir)?;
}

Type guard

fn log_file_writable(path: &str) -> bool {
    std::path::Path::new(path).parent().map(|d| d.is_dir()).unwrap_or(false)
        && std::fs::OpenOptions::new().append(true).create(true).open(path).is_ok()
}

Try / catch

match std::fs::File::create(&args.log_file) {
    Ok(f) => init_with_file(f),
    Err(e) => { eprintln!("log file unavailable ({}), falling back to stderr", e); init_stderr_only(); }
}

Prevention

When it happens

Trigger: Calling setup_tracing with CliArgs::log_file pointing to a path that cannot be created: non-existent parent directory, no write permission, path is a directory, read-only filesystem, or disk full.

Common situations: User passes --log-file /var/log/lore.log without root; typo'd path so the parent dir doesn't exist; container with read-only filesystem; log path colliding with an existing directory.

Understand the failure class

Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.

Related errors


AI-assisted analysis of EpicGames/lore@074eb0b0d1 (2026-09-13). Data as JSON: /api/errors/2d575d0c32d45238. Report an issue: GitHub.

Appendix: source

Thrown at lore-chaos-client/src/tracing.rs:13

// SPDX-FileCopyrightText: 2026 Epic Games, Inc.
// SPDX-License-Identifier: MIT
use tracing::level_filters::LevelFilter;
use tracing_subscriber::Layer;
use tracing_subscriber::fmt::layer;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;

use crate::cli::CliArgs;

pub fn setup_tracing(args: &CliArgs) {
    let log_file_layer = std::fs::File::create(&args.log_file)
        .unwrap_or_else(|_| panic!("Failed to open log file {}", args.log_file));

    let log_layer = layer()
        .pretty()
        .with_writer(log_file_layer)
        .with_ansi(false)
        .with_filter(LevelFilter::INFO);

    let stdout_filter = if args.log_to_console {
        LevelFilter::INFO
    } else {
        LevelFilter::WARN
    };
    let stdout_layer = tracing_subscriber::fmt::layer().with_filter(stdout_filter);

    tracing_subscriber::registry()
        .with(log_layer)
        .with(stdout_layer)
        .init();

View on GitHub (pinned to 074eb0b0d1)