sipeed/picoclaw · error
failed to create log file: %s
Error message
failed to create log file: %s
What it means
After the directory is ensured, InitPanic delegates to the platform-specific initPanicFile(filePath) (panic_unix.go / panic_win.go), which opens the panic log file and returns nil on any open failure. This error is raised when that writer comes back nil — the message prints only the path, so the actual OS error (permissions, EISDIR, EROFS, name too long) is swallowed by the platform helper and must be diagnosed externally.
Source
Thrown at pkg/logger/panic.go:20
import (
"fmt"
"io"
"os"
"path/filepath"
"runtime/debug"
"time"
)
var panicWriter io.WriteCloser
func InitPanic(filePath string) (func(), error) {
if err := os.MkdirAll(filepath.Dir(filePath), 0o755); err != nil {
return nil, fmt.Errorf("failed to create log directory: %w", err)
}
writer := initPanicFile(filePath)
if writer == nil {
return nil, fmt.Errorf("failed to create log file: %s", filePath)
}
if panicWriter != nil {
_ = panicWriter.Close()
}
panicWriter = writer
return func() {
defer func() {
writer.Close()
panicWriter = nil
}()
if err := recover(); err != nil {
RecoverPanicNoExit(err)
os.Exit(1)
}
}, nil
}
View on GitHub (pinned to 49183d7e8d)
Solutions
- Manually test writability of the exact path as the running user (touch <path>) to surface the real OS error
- Fix ownership/permissions of the existing file or delete it so it can be recreated
- Choose a writable absolute path on a writable filesystem
- If diagnosing a hardened host, check audit logs (SELinux/AppArmor) for the denied open
Example fix
# before
InitPanic("/var/log/picoclaw/panic.log") # returns nil-writer error, cause hidden
# after: reproduce the hidden error, then fix ownership
$ sudo -u appuser touch /var/log/picoclaw/panic.log
# touch: cannot touch ...: Permission denied
$ sudo chown appuser /var/log/picoclaw/panic.log Defensive patterns
Strategy: validation
Validate before calling
// reproduce the hidden open error before relying on panic capture
f, err := os.OpenFile(panicPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644)
if err != nil {
return fmt.Errorf("panic log %s not openable (real cause: %w)", panicPath, err)
}
f.Close() Try / catch
if _, err := logger.InitPanic(panicPath); err != nil {
// message only carries the path — the errno is lost, so probe the path directly for diagnosis
fmt.Fprintf(os.Stderr, "panic capture failed for %s; probe the path for the real error: %v\n", panicPath, err)
} Prevention
- Verify the panic log path is creatable as the running user during deployment checks
- Watch for root-owned panic logs after any privileged run and chown them back
When it happens
Trigger: The file open inside initPanicFile failing: existing panic.log owned by another user (prior sudo run), filePath naming a directory, read-only filesystem, SELinux/AppArmor denial, ENAMETOOLONG. Because the helper discards the errno, callers only learn that creation failed for that path.
Common situations: Root-owned panic.log after earlier privileged runs; log location on a read-only volume; MAC (SELinux) blocking the open with no errno surfaced to the caller.
Related errors
- failed to create log directory: %w
- failed to create log directory: %w
- failed to open log file: %w
- error in open panic: %v
- error initializing panic log: %v
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/264cac2d8a2b3f6a.
Report an issue: GitHub.