ipfs/kubo · error
not a directory: %s
Error message
not a directory: %s
What it means
unlinkNodeIfExists resolves the parent of the target path and asserts it is an *mfs.Directory. If the resolved parent is some other node type (e.g. an MFS file used as an intermediate path component), it returns "not a directory: <dir>". This is raised from `ipfs files cp --force` when trying to unlink an existing destination.
Source
Thrown at core/commands/files.go:651
if p, err := path.NewPathFromURI(arg); err == nil {
return p.String(), nil
}
return checkPath(arg)
}
func unlinkNodeIfExists(node *core.IpfsNode, path string) error {
dir, name := gopath.Split(path)
parent, err := mfs.Lookup(node.FilesRoot, dir)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil
}
return err
}
pdir, ok := parent.(*mfs.Directory)
if !ok {
return fmt.Errorf("not a directory: %s", dir)
}
// Attempt to unlink if child is a file, ignore error since
// we are only concerned with unlinking an existing file.
child, err := pdir.Child(name)
if err != nil {
return nil // no child file, nothing to unlink
}
if child.Type() != mfs.TFile {
return fmt.Errorf("not a file: %s", path)
}
return pdir.Unlink(name)
}
type filesLsOutput struct {
Entries []mfs.NodeListingView on GitHub (pinned to 329838acdf)
Solutions
- Inspect the path components: `ipfs files stat /file.txt` to find the non-directory component
- Remove or rename the offending file: `ipfs files rm /file.txt` and `ipfs files mkdir` a directory in its place
- Re-run `ipfs files cp --force` with a corrected dst path
- Use `ipfs files ls /` to verify the intended directory tree structure
Example fix
// before ipfs files cp --force /ipfs/Qm... /notes.txt/todo // error: not a directory: /notes.txt // after ipfs files mkdir /notes ipfs files cp --force /ipfs/Qm... /notes/todo
Defensive patterns
Strategy: validation
Validate before calling
// every dst component except the last must be a directory
for _, dir := range allParents(dst) {
if t := pathType(dir); t != "directory" {
return fmt.Errorf("%s is a %s, not a directory", dir, t)
}
} Type guard
func isMFSDirectory(p string) bool {
out, err := run("ipfs", "files", "stat", p)
return err == nil && strings.Contains(out, "directory")
} Try / catch
if err := ipfsFilesCpForce(src, dst); err != nil {
if strings.Contains(err.Error(), "not a directory") {
// fix the path: replace the file component with a directory
}
} Prevention
- `ipfs files ls` each path segment when constructing nested dst paths
- Avoid names that could shadow directories with files
- Build MFS trees with explicit `ipfs files mkdir` calls
When it happens
Trigger: Running `ipfs files cp --force <src> /file.txt/child` where /file.txt exists but is a file, not a directory, so resolving the parent returns a non-directory MFS node.
Common situations: dst path with a file as an intermediate component; typo'd dst where a filename was meant to be a folder name; MFS tree corrupted so a directory path resolves to a file node.
Related errors
- %s: %w
- %s and %s options are not compatible
- %s: cannot add unnamed files to MFS
- %s: MFS destination directory %q does not exist: %w
- %s: MFS destination %q is not a directory
AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03).
Data as JSON: /api/errors/bf032fa0493c323f.
Report an issue: GitHub.