{"record":{"id":"23bf4aba8310706b","repo":"sipeed/picoclaw","slug":"failed-to-create-log-directory-w-23bf4a","errorCode":null,"errorMessage":"failed to create log directory: %w","messagePattern":"failed to create log directory: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/logger/panic.go","lineNumber":16,"sourceCode":"package logger\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime/debug\"\n\t\"time\"\n)\n\nvar panicWriter io.WriteCloser\n\nfunc InitPanic(filePath string) (func(), error) {\n\tif err := os.MkdirAll(filepath.Dir(filePath), 0o755); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create log directory: %w\", err)\n\t}\n\twriter := initPanicFile(filePath)\n\tif writer == nil {\n\t\treturn nil, fmt.Errorf(\"failed to create log file: %s\", filePath)\n\t}\n\tif panicWriter != nil {\n\t\t_ = panicWriter.Close()\n\t}\n\tpanicWriter = writer\n\treturn func() {\n\t\tdefer func() {\n\t\t\twriter.Close()\n\t\t\tpanicWriter = nil\n\t\t}()\n\t\tif err := recover(); err != nil {\n\t\t\tRecoverPanicNoExit(err)\n\n\t\t\tos.Exit(1)","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/logger/panic.go#L1-L34","documentation":"InitPanic(filePath) — which installs the deferred panic-capture writer — starts with os.MkdirAll(filepath.Dir(filePath), 0o755). If the panic-log directory cannot be created, the wrapped OS error is returned and panic capture is not installed, so later panics would only reach the regular logger.","triggerScenarios":"Same failure family as EnableFileLogging's mkdir: EACCES on a protected parent (unprivileged process writing under /var/log), ENOTDIR when a path component is a file, EROFS on read-only mounts, path-length limits — triggered at startup when the panic log path is configured.","commonSituations":"Hardened deployments where the panic log points into /var/log without permissions; the panic path inherited from a config written for a different user; containers with read-only mounts.","solutions":["Point the panic log at a writable directory the process owns","Pre-create the directory with the right ownership before start","Clear any file occupying a directory component of the panic path"],"exampleFix":"# before: unprivileged process\nInitPanic(\"/var/log/picoclaw/panic.log\")\n\n# after: writable location, dir pre-created\n// install -d -o appuser /home/app/.picoclaw/logs\nInitPanic(\"/home/app/.picoclaw/logs/panic.log\")","handlingStrategy":"validation","validationCode":"if err := os.MkdirAll(filepath.Dir(panicPath), 0o755); err != nil {\n    return fmt.Errorf(\"panic log dir uncreateable — choose a writable location: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if _, err := logger.InitPanic(panicPath); err != nil {\n    fmt.Fprintf(os.Stderr, \"panic capture disabled (%v); panics will log to stderr only\\n\", err)\n}","preventionTips":["Place panic logs beside normal logs in the app-owned directory","Pre-create the directory at install time rather than relying on runtime mkdir"],"tags":["logging","filesystem","permissions","panic"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}