GoogleContainerTools/skaffold · error
unable to create directory %q: %w
Error message
unable to create directory %q: %w
What it means
The v2 event package's SaveEventsToFile mirrors the v1 behavior: it creates the target directory with os.MkdirAll(dir, 0700) before opening the file, wrapping failures as 'unable to create directory %q'. Identical causes and fixes as the v1 variant, but events come from the v2 event log.
Source
Thrown at pkg/skaffold/event/v2/event.go:318
if x.Namespace != de.Namespace || x.PodName != de.PodName || x.ContainerName != de.ContainerName {
ev.state.DebuggingContainers[n] = x
n++
}
}
ev.state.DebuggingContainers = ev.state.DebuggingContainers[:n]
}
ev.stateLock.Unlock()
}
ev.logEvent(event)
}
// 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
- Verify no regular file exists at any directory segment of the target path
- Ensure the current user has write permission on the nearest existing parent (chmod/chown or choose another location)
- Target a writable directory such as os.TempDir() or a mounted volume
- Read the wrapped syscall error (EACCES/ENOTDIR/EROFS) to identify the failing component
Example fix
// before
v2event.SaveEventsToFile("/sys/fs/cgroup/skaffold/events.json")
// after
v2event.SaveEventsToFile(filepath.Join(os.TempDir(), "skaffold-v2-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 blocks v2 event log directory", dir)
}
if err := os.MkdirAll(dir, 0700); err != nil {
return fmt.Errorf("cannot prepare v2 event log dir %q: %w", dir, err)
} Try / catch
if err := v2event.SaveEventsToFile(fp); err != nil {
var pErr *fs.PathError
if errors.As(err, &pErr) && (errors.Is(pErr.Err, fs.ErrPermission) || errors.Is(pErr.Err, syscall.EROFS)) {
log.Warnf("v2 event log destination unusable: %v", err)
return nil
}
return err
} Prevention
- Default v2 event log paths to writable temp or volume directories
- Verify path components with os.Stat before saving
- Avoid read-only and pseudo filesystems as log destinations
- Grant the running user ownership of the log directory in CI images
When it happens
Trigger: Calling pkg/skaffold/event/v2 SaveEventsToFile with a filepath whose parent directories cannot be created: no write permission, a file blocking a path component, read-only filesystem, or invalid path characters.
Common situations: Pointing the v2 event log at a read-only mount or another user's home directory; a stale regular file occupying the intended directory path; CI runners with sanitized /tmp permissions.
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/f31f49bb012dafdb.
Report an issue: GitHub.