ipfs/kubo · error

cannot remove links from a UnixFS %s node, only Directory no

Error message

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/)

What it means

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.

Source

Thrown at core/coreapi/object.go:151

	// Same validation as AddLink: dagutils.Editor operates at the dag-pb
	// level and cannot update UnixFS metadata (HAMT bitfields, Blocksizes).
	if !options.SkipUnixFSValidation {
		fsNode, err := ft.FSNodeFromBytes(basePb.Data())
		if err != nil {
			return path.ImmutablePath{}, fmt.Errorf(
				"cannot remove links from a non-UnixFS dag-pb node; " +
					"pass --allow-non-unixfs to skip validation")
		}
		switch fsNode.Type() {
		case ft.TDirectory:
			// plain directories: safe, no link-count metadata to desync
		case ft.THAMTShard:
			return path.ImmutablePath{}, fmt.Errorf(
				"cannot remove links from a HAMTShard at the dag-pb level " +
					"(would corrupt the HAMT bitfield); use 'ipfs files rm' " +
					"instead, or pass --allow-non-unixfs to override")
		default:
			return path.ImmutablePath{}, fmt.Errorf(
				"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/)",
				fsNode.Type())
		}
	}

	e := dagutils.NewDagEditor(basePb, api.dag)

	err = e.RmLink(ctx, link)
	if err != nil {
		return path.ImmutablePath{}, err
	}

	nnode, err := e.Finalize(ctx, api.dag)
	if err != nil {
		return path.ImmutablePath{}, err
	}

View on GitHub (pinned to 329838acdf)

Solutions

  1. Target a plain UnixFS directory path/CID
  2. Use 'ipfs files rm' / MFS API for content operations
  3. Use --allow-non-unixfs to force raw dag-pb removal

Example fix

// before
ipfs object patch rm-link QmFileCid link
// after
ipfs object patch rm-link QmDirCid link
Defensive patterns

Strategy: validation

Validate before calling

fsNode, err := ft.FSNodeFromBytes(pbNode.Data())
if err != nil || fsNode.Type() != ft.TDirectory {
    // only plain directories support dag-pb link removal
}

Type guard

func isPlainUnixFSDirectory(n ipld.Node) bool {
	pb, ok := n.(*dagpb.PBNode)
	if !ok { return false }
	fsn, err := ft.FSNodeFromBytes(pb.Data())
	return err == nil && fsn.Type() == ft.TDirectory
}

Prevention

When it happens

Trigger: RmLink on a resolved node whose fsNode.Type() is neither TDirectory nor THAMTShard.

Common situations: Typo in path resolves to a file node instead of the directory; attempting link removal on a UnixFS file's internal data node.

Related errors


AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03). Data as JSON: /api/errors/e46c0322905d676d. Report an issue: GitHub.