ipfs/kubo · error

cannot remove links from a HAMTShard at the dag-pb level…

Error message

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

What it means

Mirror of the AddLink HAMTShard case for removal: deleting a link from a HAMTShard via dag-pb editing would leave the HAMT bitfield and bucket structure inconsistent, breaking future lookups. RmLink refuses and directs to 'ipfs files rm' or the explicit override.

Solutions

  1. Use MFS API or 'ipfs files rm /path/in/sharded-dir'
  2. Convert the directory back to a plain directory if legacy patching is required
  3. Pass --allow-non-unixfs only with full awareness of bitfield corruption

Example fix

// before
ipfs object patch rm-link <hamt-dir-cid> child.txt
// after
ipfs files rm /my-hamt-dir/child.txt
Defensive patterns

Strategy: validation

Validate before calling

fsNode, err := ft.FSNodeFromBytes(pbNode.Data())
if err == nil && fsNode.Type() == ft.THAMTShard {
    // use 'ipfs files rm' / MFS instead of RmLink
}

Type guard

func isHAMTShard(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.THAMTShard
}

Prevention

When it happens

Trigger: RmLink on a path resolving to a UnixFS HAMTShard root with SkipUnixFSValidation=false.

Common situations: Scripts removing entries from sharded MFS root directories via the old object patch rm-link RPC after the directory was converted to a HAMT shard.

Related errors


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

Appendix: source

Thrown at core/coreapi/object.go:146

	basePb, ok := baseNd.(*dag.ProtoNode)
	if !ok {
		return path.ImmutablePath{}, dag.ErrNotProtobuf
	}

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

View on GitHub (pinned to 329838acdf)