{"record":{"id":"bf032fa0493c323f","repo":"ipfs/kubo","slug":"not-a-directory-s","errorCode":null,"errorMessage":"not a directory: %s","messagePattern":"not a directory: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/commands/files.go","lineNumber":651,"sourceCode":"\tif p, err := path.NewPathFromURI(arg); err == nil {\n\t\treturn p.String(), nil\n\t}\n\treturn checkPath(arg)\n}\n\nfunc unlinkNodeIfExists(node *core.IpfsNode, path string) error {\n\tdir, name := gopath.Split(path)\n\tparent, err := mfs.Lookup(node.FilesRoot, dir)\n\tif err != nil {\n\t\tif errors.Is(err, os.ErrNotExist) {\n\t\t\treturn nil\n\t\t}\n\t\treturn err\n\t}\n\n\tpdir, ok := parent.(*mfs.Directory)\n\tif !ok {\n\t\treturn fmt.Errorf(\"not a directory: %s\", dir)\n\t}\n\n\t// Attempt to unlink if child is a file, ignore error since\n\t// we are only concerned with unlinking an existing file.\n\tchild, err := pdir.Child(name)\n\tif err != nil {\n\t\treturn nil // no child file, nothing to unlink\n\t}\n\n\tif child.Type() != mfs.TFile {\n\t\treturn fmt.Errorf(\"not a file: %s\", path)\n\t}\n\n\treturn pdir.Unlink(name)\n}\n\ntype filesLsOutput struct {\n\tEntries []mfs.NodeListing","sourceCodeStart":633,"sourceCodeEnd":669,"githubUrl":"https://github.com/ipfs/kubo/blob/329838acdfafae224582930457efe80aa217afc0/core/commands/files.go#L633-L669","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nipfs files cp --force /ipfs/Qm... /notes.txt/todo\n// error: not a directory: /notes.txt\n\n// after\nipfs files mkdir /notes\nipfs files cp --force /ipfs/Qm... /notes/todo","handlingStrategy":"validation","validationCode":"// every dst component except the last must be a directory\nfor _, dir := range allParents(dst) {\n    if t := pathType(dir); t != \"directory\" {\n        return fmt.Errorf(\"%s is a %s, not a directory\", dir, t)\n    }\n}","typeGuard":"func isMFSDirectory(p string) bool {\n    out, err := run(\"ipfs\", \"files\", \"stat\", p)\n    return err == nil && strings.Contains(out, \"directory\")\n}","tryCatchPattern":"if err := ipfsFilesCpForce(src, dst); err != nil {\n    if strings.Contains(err.Error(), \"not a directory\") {\n        // fix the path: replace the file component with a directory\n    }\n}","preventionTips":["`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"],"tags":["mfs","cli","path-validation"],"backgroundTag":"not-a-directory","analyzedSha":"329838acdfafae224582930457efe80aa217afc0","analyzedAt":"2026-09-03T18:30:52.135Z","contentChangedAt":"2026-09-03T18:30:52.135Z","schemaVersion":2},"datasetVersion":"2026-09-11T00:17:11.886Z"}