espanso/espanso · error

unable to set up log output file

Error message

unable to set up log output file

What it means

After config loading, main attaches a log output file in the runtime directory via log_proxy.set_output_file(...).expect(...). The expect fires if opening/creating the log file fails or if the FileProxy lock is poisoned (error 143 path).

Source

Thrown at espanso/src/main.rs:625

            info!("using runtime dir: {:?}", paths.runtime.display());
            log_system_info();

            if handler.requires_config {
                let config_result = load_config(&paths.config).expect("unable to load config");

                cli_args.config_store = Some(config_result.config_store);
                cli_args.match_store = Some(config_result.match_store);
                cli_args.non_fatal_errors = config_result.non_fatal_errors;
            }

            if handler.enable_logs {
                log_proxy
                    .set_output_file(
                        &paths.runtime.join(LOG_FILE_NAME),
                        handler.log_mode == LogMode::Read,
                        handler.log_mode == LogMode::CleanAndAppend,
                    )
                    .expect("unable to set up log output file");
            }

            cli_args.paths = Some(paths);
        }

        // try to invoke `kdotool` to see if you have it or not.
        #[cfg(target_os = "linux")]
        if Command::new("kdotool")
            .arg("getactivewindow")
            .arg("getwindowclassname")
            .output()
            .is_ok()
        {
        } else {
            info!("kdotool missing or not available for the current wayland DE.");
        }

        if let Some(args) = matches.subcommand_matches(&handler.subcommand) {

View on GitHub (pinned to e6c3736675)

Solutions

  1. Recreate the runtime directory and fix permissions (`espanso path` shows it; typically `mkdir -p <runtime>` and chown to the running user).
  2. Check disk space (df -h) if the filesystem is full.
  3. Run espanso as the same user that owns the runtime dir; avoid mixing sudo/non-sudo runs.
  4. Verify the earlier panic (if 'unable to obtain FileProxy lock' preceded this) and fix its root cause.
  5. Update or patch espanso to degrade gracefully (keep memory-only logging) when the file can't be opened.

Example fix

// before
log_proxy
    .set_output_file(&paths.runtime.join(LOG_FILE_NAME), read, clean)
    .expect("unable to set up log output file");
// after
if let Err(err) = log_proxy.set_output_file(&paths.runtime.join(LOG_FILE_NAME), read, clean) {
    eprintln!("warning: falling back to memory logging: {err}");
}
Defensive patterns

Strategy: fallback

Validate before calling

let log_path = paths.runtime.join(LOG_FILE_NAME);
if let Err(e) = std::fs::OpenOptions::new().append(true).create(true).open(&log_path) {
    eprintln!("cannot write log file {}: {e}", log_path.display());
}

Try / catch

if let Err(e) = log_proxy.set_output_file(&log_path, read, clean) {
    eprintln!("warning: memory-only logging: {e}");
}

Prevention

When it happens

Trigger: set_output_file returns Err: the runtime directory doesn't exist, is read-only, or denies write permission; disk full; or the underlying Mutex is poisoned from an earlier panic (LogMode::Read / CleanAndAppend flags passed from the handler).

Common situations: Runtime dir deleted or mounted read-only (sandboxed/Flatpak setups, read-only /run), permission mismatch after running espanso as different users, disk-full, or a prior panic poisoning the log mutex.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of espanso/espanso@e6c3736675 (2026-09-06). Data as JSON: /api/errors/69951eba95e7c9d4. Report an issue: GitHub.