GoogleContainerTools/skaffold · error
unable to create directory %q: %w
Error message
unable to create directory %q: %w
What it means
SaveEventsToFile persists the in-memory event log to a JSON file. It first creates the parent directories of the provided filepath with os.MkdirAll(dir, 0700); if that fails the error is wrapped as 'unable to create directory %q'. This usually indicates a filesystem-level problem, not a skaffold bug.
Source
Thrown at pkg/skaffold/event/event.go:837
func InititializationFailed(err error) {
handler.handle(&proto.Event{
EventType: &proto.Event_TerminationEvent{
TerminationEvent: &proto.TerminationEvent{
Status: Failed,
Err: sErrors.ActionableErr(handler.cfg, constants.Init, err),
},
},
})
}
// SaveEventsToFile saves the current event log to the filepath provided
func SaveEventsToFile(fp string) error {
handler.logLock.Lock()
// Ensure that the filepath provided has the directories available when attemping to save the file.
dir := filepath.Dir(fp)
if err := os.MkdirAll(dir, 0700); err != nil {
return fmt.Errorf("unable to create directory %q: %w", dir, err)
}
f, err := os.OpenFile(fp, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
return fmt.Errorf("opening %s: %w", fp, err)
}
defer f.Close()
marshaller := jsonpb.Marshaler{}
for _, ev := range handler.eventLog {
contents := bytes.NewBuffer([]byte{})
if err := marshaller.Marshal(contents, ev); err != nil {
return fmt.Errorf("marshalling event: %w", err)
}
if _, err := f.WriteString(contents.String() + "\n"); err != nil {
return fmt.Errorf("writing string: %w", err)
}
}
handler.logLock.Unlock()
return nilView on GitHub (pinned to a1189de023)
Solutions
- Check whether a file exists at any segment of the target directory path and remove/rename it
- Verify write permission on the nearest existing parent directory (ls -ld <dir>)
- Write the event log to a writable location (e.g. $HOME or a mounted volume) instead of a read-only path
- Inspect the wrapped inner error (ENOENT/EACCES/ENOTDIR) to pinpoint which path component fails
Example fix
// before
SaveEventsToFile("/proc/1/events.json")
// after
SaveEventsToFile(filepath.Join(os.TempDir(), "skaffold-events.json")) Defensive patterns
Strategy: validation
Validate before calling
dir := filepath.Dir(fp)
if info, err := os.Stat(dir); err == nil && !info.IsDir() {
return fmt.Errorf("%s exists and is not a directory", dir)
}
if err := os.MkdirAll(dir, 0700); err != nil {
return fmt.Errorf("pre-check mkdir failed: %w", err)
} Try / catch
if err := SaveEventsToFile(fp); err != nil {
var pErr *fs.PathError
if errors.As(err, &pErr) {
log.Warnf("event log not saved (%s: %v), continuing", pErr.Path, pErr.Err)
return nil
}
return err
} Prevention
- Choose event-log destinations under a guaranteed-writable directory (os.TempDir, $HOME)
- Never point the log path at special filesystems (/proc, /sys)
- Ensure no regular file occupies a directory segment of the path
- In containers, mount a volume for logs
When it happens
Trigger: Calling SaveEventsToFile with a path whose parent directory cannot be created: missing parent write permission, a file component existing where a directory is expected (ENOTDIR/EEXIST), read-only filesystem, or an invalid path component.
Common situations: Passing an event log path inside a read-only container filesystem or read-only mount; a regular file already occupies a path segment of the target directory; running as a user without write access to the output location; disk full on tmpfs.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05).
Data as JSON: /api/errors/6bd5f9c6ab08f90c.
Report an issue: GitHub.