sipeed/picoclaw · error
failed to create log directory: %w
Error message
failed to create log directory: %w
What it means
EnableFileLogging first ensures the parent directory of the requested log file exists via os.MkdirAll(filepath.Dir(filePath), 0o755). If that mkdir fails, the wrapped OS error is returned and file logging is never enabled (the package keeps its previous sink; the mutex-guarded state is unchanged).
Source
Thrown at pkg/logger/logger.go:181
}
// SetLevelFromString sets the log level from a string value.
// If the string is empty or not a recognized level name, the current level is kept.
func SetLevelFromString(s string) {
if s == "" {
return
}
if level, ok := ParseLevel(s); ok {
SetLevel(level)
}
}
func EnableFileLogging(filePath string) error {
mu.Lock()
defer mu.Unlock()
if err := os.MkdirAll(filepath.Dir(filePath), 0o755); err != nil {
return fmt.Errorf("failed to create log directory: %w", err)
}
newFile, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644)
if err != nil {
return fmt.Errorf("failed to open log file: %w", err)
}
// Close old file if exists
if logFile != nil {
logFile.Close()
}
logFile = newFile
if len(writers) != 1 {
return fmt.Errorf("failed to configure file logging: %w", err)
}
View on GitHub (pinned to 49183d7e8d)
Solutions
- Choose a log path under a directory the process can write to (e.g. within the instance/data dir)
- Pre-create the directory with correct ownership (install -d -o app /var/log/app)
- Remove any regular file occupying a needed directory component
- Use an absolute filePath so the parent dir does not depend on the working directory
Example fix
# before
EnableFileLogging("/var/log/picoclaw/app.log") # unprivileged user
# after
EnableFileLogging("/home/app/.picoclaw/logs/app.log") Defensive patterns
Strategy: validation
Validate before calling
func logDirReady(path string) bool {
dir := filepath.Dir(path)
if err := os.MkdirAll(dir, 0o755); err != nil {
return false
}
probe := filepath.Join(dir, ".probe")
if err := os.WriteFile(probe, nil, 0o644); err != nil {
return false
}
_ = os.Remove(probe)
return true
} Try / catch
if err := logger.EnableFileLogging(path); err != nil {
// keep the process alive on stdout/stderr logging, but surface the misconfiguration
fmt.Fprintf(os.Stderr, "file logging unavailable (%v); continuing on stderr\n", err)
} Prevention
- Default log paths into an app-owned directory instead of /var/log
- Create log directories in the install/package step with correct ownership
- Always pass absolute log paths so behavior does not depend on cwd
When it happens
Trigger: (1) EACCES: log directory path under a root-owned or non-writable parent (e.g. /var/log without privileges); (2) ENOTDIR: a path component is a regular file ("/tmp/x" is a file, log path "/tmp/x/app.log"); (3) EROFS: read-only filesystem; (4) relative filePath whose parent resolves against an unexpected cwd; (5) ENAMETOOLONG.
Common situations: Pointing log_file at /var/log/... while running unprivileged; running under systemd without WriteDirectories/permissions; a stale file squatting on a directory name; read-only container mounts for config-derived log paths.
Related errors
- failed to open log file: %w
- failed to create log directory: %w
- failed to create log file: %s
- create output dir: %w
- failed to save config: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/49111e2cb0618681.
Report an issue: GitHub.