{"record":{"id":"5218291cfded1c92","repo":"ruby/ruby","slug":"failed-to-create-log-file-path-err","errorCode":null,"errorMessage":"Failed to create {log_file_path}: {err}","messagePattern":"Failed to create (.+?): (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"yjit/src/options.rs","lineNumber":360,"sourceCode":"                OPTIONS.log = Some(LogOutput::MemoryOnly);\n                Log::init();\n            },\n            arg_value => {\n                let log_file_path = if std::path::Path::new(arg_value).is_dir() {\n                    format!(\"{arg_value}/yjit_{}.log\", std::process::id())\n                } else {\n                    arg_value.to_string()\n                };\n\n                match File::options().create(true).write(true).truncate(true).open(&log_file_path) {\n                    Ok(file) => {\n                        use std::os::unix::io::IntoRawFd;\n                        eprintln!(\"YJIT log: {log_file_path}\");\n\n                        unsafe { OPTIONS.log = Some(LogOutput::File(file.into_raw_fd())) }\n                        Log::init()\n                    }\n                    Err(err) => panic!(\"Failed to create {log_file_path}: {err}\"),\n                }\n            }\n        },\n        (\"trace-exits\", _) => unsafe {\n            OPTIONS.gen_stats = true;\n            OPTIONS.trace_exits = match opt_val {\n                \"\" => Some(TraceExits::All),\n                name => match Counter::get(name) {\n                    Some(counter) => Some(TraceExits::Counter(counter)),\n                    None => return None,\n                },\n            };\n        },\n        (\"trace-exits-sample-rate\", sample_rate) => unsafe {\n            OPTIONS.gen_stats = true;\n            if OPTIONS.trace_exits.is_none() {\n                OPTIONS.trace_exits = Some(TraceExits::All);\n            }","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/ruby/ruby/blob/0e5b888e1c355f3f728f2659f085820937dada48/yjit/src/options.rs#L342-L378","documentation":"When YJIT is given a log file (--yjit-log=/path or RubyVM::YJIT.enable(log: '/path')), option processing opens it with create+write+truncate before your program runs. If the open fails — missing parent directory, permission denied, path is a directory — the Rust code panics with this message, which aborts the whole ruby process. The panic embeds the underlying OS error string, so the exact cause is visible.","triggerScenarios":"--yjit-log=/var/log/yjit.log without write permission; --yjit-log=out/yjit.log when out/ does not exist; a log path that points at a directory; a relative path resolved from a cwd that cannot host files (systemd, cron, container read-only fs).","commonSituations":"CI sandboxes with read-only or missing directories; wrapper scripts assuming a different working directory than the service manager uses; the application creating its log dir after Ruby startup has already processed YJIT options.","solutions":["Create the parent directory first: mkdir -p the directory portion of the log path","Use an absolute path to a known-writable location such as $TMPDIR for --yjit-log","Read the errno embedded in the panic (Permission denied vs No such file or directory) and fix ownership/permissions accordingly","Drop --yjit-log entirely if the log is optional"],"exampleFix":"# before\nruby --yjit --yjit-log=logs/yjit.log app.rb  # panics when logs/ is missing\n\n# after\nmkdir -p logs && ruby --yjit --yjit-log=logs/yjit.log app.rb","handlingStrategy":"validation","validationCode":"# Guard before enabling the YJIT log\nlog_path = ENV['YJIT_LOG']\nif log_path\n  dir = File.dirname(File.expand_path(log_path))\n  unless File.directory?(dir) && File.writable?(dir)\n    require 'fileutils'\n    FileUtils.mkdir_p(dir) rescue log_path = nil  # fall back to no log file\n  end\nend\nRubyVM::YJIT.enable(log: log_path)","typeGuard":null,"tryCatchPattern":"Not rescuable from Ruby: the failure is a Rust panic during option processing, which aborts the process. Prevent it by validating the path (directory exists and is writable) before passing --yjit-log / enable(log:), and fall back to stderr logging when validation fails.","preventionTips":["Always mkdir -p the log directory in wrapper scripts before starting ruby with --yjit-log","Prefer absolute paths derived from a known base (Dir.tmpdir, app root) over bare relative paths","Treat a YJIT log panic as a configuration failure: fail fast in the entrypoint, not mid-deploy"],"tags":["ruby","yjit","logging","file-permissions","rust-panic","startup-crash"],"backgroundTag":"log-file-creation-failed","analyzedSha":"0e5b888e1c355f3f728f2659f085820937dada48","analyzedAt":"2026-08-21T14:25:43.473Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}