shadowsocks/shadowsocks-rust · error
Failed to create file writer for logging
Error message
Failed to create file writer for logging
What it means
Panic when the tracing-based logging subsystem cannot create the file writer for a file-logging layer in make_layer: make_file_writer(bin_name, self) returned Err (unwritable/missing directory, permission denied, disk error) and expect('Failed to create file writer for logging') panics, as noted by the inline comment about the lack of graceful handling.
Solutions
- Verify the log directory exists and is writable by the process user before startup
- Use an absolute log file path in the config and create the directory in your launch script
- Fall back to console logging if the file writer fails (patch or wrap make_layer)
- Run as a user with correct permissions or adjust log-dir ownership
Example fix
// before
let file_writer = make_file_writer(bin_name, self)
.expect("Failed to create file writer for logging");
// after
std::fs::create_dir_all(&log_dir)?;
let file_writer = make_file_writer(bin_name, self)
.unwrap_or_else(|e| {
eprintln!("file logging disabled: {}", e);
make_console_writer()
}); Defensive patterns
Strategy: fallback
Validate before calling
fn ensure_log_dir_writable(dir: &Path) -> Result<(), String> {
std::fs::create_dir_all(dir).map_err(|e| format!("cannot create log dir {:?}: {}", dir, e))?;
let probe = dir.join(".write_probe");
std::fs::write(&probe, b"").map_err(|e| format!("log dir {:?} not writable: {}", dir, e))?;
let _ = std::fs::remove_file(&probe);
Ok(())
} Try / catch
// expect() panics; pre-flight the directory and fall back to console logging on failure
let file_writer = match make_file_writer(bin_name, self) {
Ok(w) => w,
Err(e) => { eprintln!("file logging unavailable: {}", e); return make_console_layer(); }
}; Prevention
- Create the log directory in your service/launcher before starting the binary
- Run the process with a user that owns the log directory
- Use absolute log paths to survive daemonization cwd changes
- Add a startup smoke test that writes and deletes a probe file in the log dir
When it happens
Trigger: Configuring a file logger (LogConfig with file output / LogTracingFileConfig) where the log directory doesn't exist, is not writable, or a rotation path is invalid; make_layer then panics while assembling the layer stack.
Common situations: Daemon running as an unprivileged user with a log dir owned by root; misconfigured log-file path (relative path resolving under a read-only cwd); disk-full or deleted log directory at startup.
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 shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09).
Data as JSON: /api/errors/0d2e33b80b85caf2.
Report an issue: GitHub.
Appendix: source
Thrown at src/logging/tracing.rs:66
}
impl MakeLayer for LogConsoleWriterConfig {
fn make_layer(&self, bin_name: &str, global: &LogConfig) -> BoxedLayer {
let level = self.level.unwrap_or(global.level);
let format = apply_override(&global.format, &self.format);
let ansi = io::stdout().is_terminal();
make_fmt_layer(bin_name, level, &format, ansi, io::stdout)
}
}
impl MakeLayer for LogFileWriterConfig {
fn make_layer(&self, bin_name: &str, global: &LogConfig) -> BoxedLayer {
let level = self.level.unwrap_or(global.level);
let format = apply_override(&global.format, &self.format);
let file_writer = make_file_writer(bin_name, self)
// don't have the room for a more graceful error handling here
.expect("Failed to create file writer for logging");
make_fmt_layer(bin_name, level, &format, false, file_writer)
}
}
#[cfg(unix)]
impl MakeLayer for LogSyslogWriterConfig {
fn make_layer(&self, bin_name: &str, global: &LogConfig) -> BoxedLayer {
let level = self.level.unwrap_or(global.level);
let format = apply_override(&global.format, &self.format);
let syslog_writer = make_syslog_writer(bin_name, self);
make_fmt_layer(bin_name, level, &format, false, syslog_writer)
}
}
/// Boilerplate for configuring a `fmt::Layer` with `level` and `format` for different writers.
fn make_fmt_layer<W>(bin_name: &str, level: u32, format: &LogFormatConfig, ansi: bool, writer: W) -> BoxedLayer
whereView on GitHub (pinned to 8eb0f0a65b)