{"record":{"id":"e46c0322905d676d","repo":"ipfs/kubo","slug":"cannot-remove-links-from-a-unixfs-s-node-only-di","errorCode":null,"errorMessage":"cannot remove links from a UnixFS %s node, only Directory nodes support link removal at the dag-pb level (see https://specs.ipfs.tech/unixfs/)","messagePattern":"cannot remove links from a UnixFS (.+?) node, only Directory nodes support link removal at the dag-pb level \\(see https://specs\\.ipfs\\.tech/unixfs/\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/coreapi/object.go","lineNumber":151,"sourceCode":"\t// Same validation as AddLink: dagutils.Editor operates at the dag-pb\n\t// level and cannot update UnixFS metadata (HAMT bitfields, Blocksizes).\n\tif !options.SkipUnixFSValidation {\n\t\tfsNode, err := ft.FSNodeFromBytes(basePb.Data())\n\t\tif err != nil {\n\t\t\treturn path.ImmutablePath{}, fmt.Errorf(\n\t\t\t\t\"cannot remove links from a non-UnixFS dag-pb node; \" +\n\t\t\t\t\t\"pass --allow-non-unixfs to skip validation\")\n\t\t}\n\t\tswitch fsNode.Type() {\n\t\tcase ft.TDirectory:\n\t\t\t// plain directories: safe, no link-count metadata to desync\n\t\tcase ft.THAMTShard:\n\t\t\treturn path.ImmutablePath{}, fmt.Errorf(\n\t\t\t\t\"cannot remove links from a HAMTShard at the dag-pb level \" +\n\t\t\t\t\t\"(would corrupt the HAMT bitfield); use 'ipfs files rm' \" +\n\t\t\t\t\t\"instead, or pass --allow-non-unixfs to override\")\n\t\tdefault:\n\t\t\treturn path.ImmutablePath{}, fmt.Errorf(\n\t\t\t\t\"cannot remove links from a UnixFS %s node, \"+\n\t\t\t\t\t\"only Directory nodes support link removal at the dag-pb level \"+\n\t\t\t\t\t\"(see https://specs.ipfs.tech/unixfs/)\",\n\t\t\t\tfsNode.Type())\n\t\t}\n\t}\n\n\te := dagutils.NewDagEditor(basePb, api.dag)\n\n\terr = e.RmLink(ctx, link)\n\tif err != nil {\n\t\treturn path.ImmutablePath{}, err\n\t}\n\n\tnnode, err := e.Finalize(ctx, api.dag)\n\tif err != nil {\n\t\treturn path.ImmutablePath{}, err\n\t}","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/ipfs/kubo/blob/329838acdfafae224582930457efe80aa217afc0/core/coreapi/object.go#L133-L169","documentation":"RmLink only supports plain UnixFS Directory nodes at the dag-pb level; any other UnixFS type (file, raw, symlink, etc.) cannot have named links removed meaningfully. The message includes the offending node type and links the UnixFS spec.","triggerScenarios":"RmLink on a resolved node whose fsNode.Type() is neither TDirectory nor THAMTShard.","commonSituations":"Typo in path resolves to a file node instead of the directory; attempting link removal on a UnixFS file's internal data node.","solutions":["Target a plain UnixFS directory path/CID","Use 'ipfs files rm' / MFS API for content operations","Use --allow-non-unixfs to force raw dag-pb removal"],"exampleFix":"// before\nipfs object patch rm-link QmFileCid link\n// after\nipfs object patch rm-link QmDirCid link","handlingStrategy":"validation","validationCode":"fsNode, err := ft.FSNodeFromBytes(pbNode.Data())\nif err != nil || fsNode.Type() != ft.TDirectory {\n    // only plain directories support dag-pb link removal\n}","typeGuard":"func isPlainUnixFSDirectory(n ipld.Node) bool {\n\tpb, ok := n.(*dagpb.PBNode)\n\tif !ok { return false }\n\tfsn, err := ft.FSNodeFromBytes(pb.Data())\n\treturn err == nil && fsn.Type() == ft.TDirectory\n}","tryCatchPattern":null,"preventionTips":["Resolve and type-check the target before RmLink","Use 'ipfs files rm' for files and other UnixFS types","Restrict object patch usage to plain directories in scripts"],"tags":["unixfs","dag-pb","node-type","deprecated-api"],"backgroundTag":"unixfs-non-directory-link-edit","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"}