ahmetb/kubectx · error
failed to open file %q: %w
Error message
failed to open file %q: %w
What it means
StandardKubeconfigLoader.Load opens each candidate kubeconfig path with os.OpenFile(..., os.O_RDWR, 0). Paths that don't exist are silently skipped, but any other open error (permissions, is-a-directory, device errors) aborts with this error wrapping the original *os.PathError, which names the failing path in %q and the syscall error in %w.
Source
Thrown at internal/kubeconfig/kubeconfigloader.go:52
path string
}
func (kf *kubeconfigFile) Path() string { return kf.path }
func (*StandardKubeconfigLoader) Load() ([]ReadWriteResetCloser, error) {
paths, err := kubeconfigPaths()
if err != nil {
return nil, fmt.Errorf("cannot determine kubeconfig path: %w", err)
}
var files []ReadWriteResetCloser
for _, p := range paths {
f, err := os.OpenFile(p, os.O_RDWR, 0)
if err != nil {
if os.IsNotExist(err) {
continue
}
return nil, fmt.Errorf("failed to open file %q: %w", p, err)
}
files = append(files, &kubeconfigFile{File: f, path: p})
}
if len(files) == 0 {
return nil, fmt.Errorf("kubeconfig file not found: %w",
&os.PathError{Op: "open", Path: paths[0], Err: os.ErrNotExist})
}
return files, nil
}
func (kf *kubeconfigFile) Reset() error {
if err := kf.Truncate(0); err != nil {
return fmt.Errorf("failed to truncate file: %w", err)
}
if _, err := kf.Seek(0, 0); err != nil {
return fmt.Errorf("failed to seek in file: %w", err)
}
return nilView on GitHub (pinned to 12ad6fb22e)
Solutions
- Read the wrapped *os.PathError in %w for the exact path and errno, then chmod/chown the file to be writable by the current user
- If the path should not be opened, unset it from KUBECONFIG: export KUBECONFIG="$HOME/.kube/config"
- If the path is a directory, point KUBECONFIG at actual files only (colon-separated)
- Verify the file is not on a read-only/failed mount (ls -l, mount, df)
Example fix
// before export KUBECONFIG=/root/.kube/config # permission denied for current user // after export KUBECONFIG=$HOME/.kube/config
Defensive patterns
Strategy: validation
Validate before calling
// Go
for _, p := range paths {
if fi, err := os.Stat(p); err == nil {
if fi.IsDir() { return fmt.Errorf("%s is a directory", p) }
if f, err := os.OpenFile(p, os.O_RDWR, 0); err != nil {
return fmt.Errorf("%s not openable read-write: %v", p, err)
} else { f.Close() }
}
} Type guard
func isPermissionErr(err error) bool {
return errors.Is(err, os.ErrPermission)
} Try / catch
files, err := loader.Load()
var pe *fs.PathError
if errors.As(err, &pe) {
return fmt.Errorf("cannot open %s: %v — check permissions", pe.Path, pe.Err)
} Prevention
- Keep kubeconfig files at 0600 owned by the running user
- Never point KUBECONFIG at directories or root-owned files when running unprivileged
- Clean stale entries out of KUBECONFIG periodically
- Check mount status (ro flag) for network filesystems
When it happens
Trigger: Calling Load when a path from $KUBECONFIG (or the default ~/.kube/config) exists but cannot be opened for reading and writing — e.g. permission denied (chmod 000 / root-owned file), the path is a directory, or an I/O error occurs.
Common situations: KUBECONFIG pointing at a file owned by another user or with 0600 root-only permissions; a stale KUBECONFIG entry that now names a directory; file locked on a network share; running the tool unprivileged against another user's config.
Related errors
- failed to truncate file: %w
- failed to seek in file: %w
- kubeconfig error: %w
- failed to get current context: %w
- failed to read namespace of "%s": %w
AI-assisted analysis of ahmetb/kubectx@12ad6fb22e (2026-09-02).
Data as JSON: /api/errors/88a99f6aedf22f9d.
Report an issue: GitHub.