kubernetes/kops · error
not a directory: %q
Error message
not a directory: %q
What it means
mkdirAll verifies that each path component exists and is a directory before writing a file over SFTP. When Lstat succeeds for `dir` but the entry is a regular file, symlink-to-file, or other non-directory, the function aborts with this error instead of silently proceeding. It exists to give a clear message rather than confusing Mkdir/Create failures downstream.
Source
Thrown at util/pkg/vfs/sshfs.go:153
}
func (p *SSHPath) Join(relativePath ...string) Path {
args := []string{p.path}
args = append(args, relativePath...)
joined := path.Join(args...)
return NewSSHPath(p.client, p.server, joined, p.sudo)
}
func mkdirAll(sftpClient *sftp.Client, dir string) error {
if dir == "/" {
// Must always exist
return nil
}
stat, err := sftpClient.Lstat(dir)
if err == nil {
if !stat.IsDir() {
return fmt.Errorf("not a directory: %q", dir)
}
return nil
}
parent := path.Dir(dir)
err = mkdirAll(sftpClient, parent)
if err != nil {
return err
}
err = sftpClient.Mkdir(dir)
if err != nil {
return fmt.Errorf("error creating directory %q over sftp: %w", dir, err)
}
return nil
}
func (p *SSHPath) WriteFile(ctx context.Context, data io.ReadSeeker, acl ACL) error {View on GitHub (pinned to 4c8573c808)
Solutions
- SSH to the remote host and inspect the offending path (`ls -la <dir>`); remove or rename the file that occupies the directory name (`mv <dir> <dir>.bak` or `rm <dir>`).
- Recreate the path as a directory: `mkdir -p <dir>` on the remote host, then retry the kOps operation.
- Fix the SSHPath construction in your tooling so the target parent path points at an actual directory.
- If a symlink is involved, repoint it (`ln -sfn <realdir> <dir>`) so it resolves to a directory.
Example fix
// before (remote host has a file where a directory is needed) $ ls -la /etc/kubernetes -rw-r--r-- 1 root root 12 config // after $ rm /etc/kubernetes/config && mkdir -p /etc/kubernetes/config
Defensive patterns
Strategy: validation
Validate before calling
// check remote parent path is a directory before writing
sftp, err := newSFTPClient(ctx)
if err != nil { return err }
if stat, err := sftp.Lstat(dir); err == nil && !stat.IsDir() {
return fmt.Errorf("precheck: %q exists and is not a directory", dir)
} Prevention
- Before provisioning, verify no file occupies paths you will use as directories (`ls -la` over SSH).
- Keep node paths (/etc/kubernetes/...) free of ad-hoc files created by other tooling.
- Build SSHPath targets programmatically from a single source of truth to avoid path typos.
When it happens
Trigger: Calling WriteFile (via CreateFile) on an SSHPath whose parent path component is an existing non-directory, e.g. writing to /etc/kubernetes/config where /etc/kubernetes is a regular file on the remote host.
Common situations: A previously created config file now collides with a directory kOps needs (e.g. state store path conflicts); a stray file was created where a directory was expected; symlink pointing at a file; wrong SSHPath prefix built by the caller.
Related errors
- error creating temp file in %q: %w
- error reading SSH public key %v: %v
- error reading /var/log: %v
- error listing %q: %v
- error creating sftp client: %w
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/3ba25528883adc93.
Report an issue: GitHub.