{"record":{"id":"6d02dd2e92f3ff00","repo":"charmbracelet/bubbletea","slug":"error-opening-file-for-logging-w","errorCode":null,"errorMessage":"error opening file for logging: %w","messagePattern":"error opening file for logging: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"logging.go","lineNumber":38,"sourceCode":"//\t\t\tos.Exit(1)\n//\t  }\n//\t  defer f.Close()\nfunc LogToFile(path string, prefix string) (*os.File, error) {\n\treturn LogToFileWith(path, prefix, log.Default())\n}\n\n// LogOptionsSetter is an interface implemented by stdlib's log and charm's log\n// libraries.\ntype LogOptionsSetter interface {\n\tSetOutput(io.Writer)\n\tSetPrefix(string)\n}\n\n// LogToFileWith does allows to call LogToFile with a custom LogOptionsSetter.\nfunc LogToFileWith(path string, prefix string, log LogOptionsSetter) (*os.File, error) {\n\tf, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o600) //nolint:mnd\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error opening file for logging: %w\", err)\n\t}\n\tlog.SetOutput(f)\n\n\t// Add a space after the prefix if a prefix is being specified and it\n\t// doesn't already have a trailing space.\n\tif len(prefix) > 0 {\n\t\tfinalChar := prefix[len(prefix)-1]\n\t\tif !unicode.IsSpace(rune(finalChar)) {\n\t\t\tprefix += \" \"\n\t\t}\n\t}\n\tlog.SetPrefix(prefix)\n\n\treturn f, nil\n}\n","sourceCodeStart":20,"sourceCodeEnd":54,"githubUrl":"https://github.com/charmbracelet/bubbletea/blob/351d2159f8d8a85613aa2a6e98c8c63df3c98623/logging.go#L20-L54","documentation":"Returned by tea.LogToFile / tea.LogToFileWith when the debug log file cannot be opened with O_WRONLY|O_CREATE|O_APPEND and mode 0600. Because a TUI occupies the terminal, file logging is the standard way to debug Bubble Tea programs; this error means that setup failed before any logging was configured. It wraps the os.OpenFile error verbatim.","triggerScenarios":"Path points to a nonexistent directory (ENOENT); permission denied (EACCES) for the file or its directory; path is a directory itself; read-only filesystem; path too long; too many open files (EMFILE).","commonSituations":"Log path like \"/tmp/tea/debug.log\" where /tmp/tea was never created; running as a user without write access to the chosen dir (e.g. /var/log); container images with read-only root filesystems; hard-coded absolute debug paths from README examples that don't exist on the machine.","solutions":["Create the parent directory first (os.MkdirAll) before calling LogToFile","Use a path you know is writable: os.TempDir(), the current dir, or XDG data/cache dirs","Check directory permissions / run with appropriate privileges if the path must be system-wide","Use tea.WithLogPath or set p.logger another way for non-file logging"],"exampleFix":"// before\nf, err := tea.LogToFile(\"/var/log/myapp/debug.log\", \"debug\")\n\n// after\ndir := filepath.Join(os.TempDir(), \"myapp\")\n_ = os.MkdirAll(dir, 0o755)\nf, err := tea.LogToFile(filepath.Join(dir, \"debug.log\"), \"debug\")","handlingStrategy":"validation","validationCode":"func openDebugLog(dir, name string) (*os.File, error) {\n    if err := os.MkdirAll(dir, 0o755); err != nil {\n        return nil, err\n    }\n    // probe writability before handing path to bubbletea\n    probe, err := os.OpenFile(filepath.Join(dir, name), os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o600)\n    if err != nil {\n        return nil, fmt.Errorf(\"log dir not writable: %w\", err)\n    }\n    return probe, nil\n}","typeGuard":null,"tryCatchPattern":"f, err := tea.LogToFile(path, \"debug\")\nif err != nil {\n    // degrade: skip file logging rather than dying\n    log.Printf(\"warning: debug logging disabled: %v\", err)\n    f = nil\n}\ndefer func() { if f != nil { f.Close() } }()","preventionTips":["Always MkdirAll the log directory first","Prefer os.TempDir() or user cache dirs over system paths like /var/log","Make debug logging optional: app should run without it","Check permissions when running under restricted service accounts"],"tags":["bubbletea","logging","filesystem","permissions","go"],"backgroundTag":null,"analyzedSha":"351d2159f8d8a85613aa2a6e98c8c63df3c98623","analyzedAt":"2026-08-15T10:48:22.366Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}