ipfs/kubo · error

cannot add links to a HAMTShard at the dag-pb level (would c

Error message

cannot add links to a HAMTShard at the dag-pb level (would corrupt the HAMT bitfield); use 'ipfs files' commands instead, or pass --allow-non-unixfs to override

What it means

CoreAPI's AddLink edits dag-pb nodes directly, which is only safe for plain UnixFS directories. A HAMTShard (a hamt-shard directory created e.g. with --hamt-encoding) stores membership in a bitfield spread across its DAG; blind dag-pb link insertion would desync it and silently corrupt lookups. The library refuses and points to the 'ipfs files' API or the --allow-non-unixfs escape hatch.

Source

Thrown at core/coreapi/object.go:78

	// This command operates at the dag-pb level via dagutils.Editor, which
	// only manipulates ProtoNode links without updating UnixFS metadata.
	// Only plain UnixFS Directory nodes are safe to mutate this way.
	// File nodes: adding links corrupts Blocksizes, content lost on read-back.
	// HAMTShard nodes: bitfield not updated, shard trie becomes inconsistent.
	// https://specs.ipfs.tech/unixfs/#pbnode-links-name
	// https://github.com/ipfs/kubo/issues/7190
	if !options.SkipUnixFSValidation {
		fsNode, err := ft.FSNodeFromBytes(basePb.Data())
		if err != nil {
			return path.ImmutablePath{}, fmt.Errorf(
				"cannot add named links to 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 add links to a HAMTShard at the dag-pb level " +
					"(would corrupt the HAMT bitfield); use 'ipfs files' " +
					"commands instead, or pass --allow-non-unixfs to override")
		default:
			return path.ImmutablePath{}, fmt.Errorf(
				"cannot add named links to a UnixFS %s node, "+
					"only Directory nodes support link addition at the dag-pb level "+
					"(see https://specs.ipfs.tech/unixfs/)",
				fsNode.Type())
		}
	}

	var createfunc func() *dag.ProtoNode
	if options.Create {
		createfunc = ft.EmptyDirNode
	}

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

View on GitHub (pinned to 329838acdf)

Solutions

  1. Use the MFS/files API (coreapi FilesAPI) to modify the directory, or CLI 'ipfs files' commands
  2. Re-create the directory as a plain UnixFS directory if dag-pb patching is truly required
  3. Set the --allow-non-unixfs option / SkipUnixFSValidation=true only if you accept corrupting the HAMT bitfield

Example fix

// before (RPC)
ipfs object patch add-link <hamt-dir-cid> child.txt <child-cid>
// after
ipfs files cp /ipfs/<child-cid> /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 {
    // route through files/MFS API instead of AddLink
}

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 && fsNode.Type() == ft.THAMTShard
}

Prevention

When it happens

Trigger: Calling PinAPI-adjacent object API AddLink (coreapi/unixfs AddLink) with SkipUnixFSValidation=false on a path whose root node is a UnixFS HAMTShard (fs.Type()==THAMTShard).

Common situations: Directories created with 'ipfs add --json' or 'ipfs files --hamt-encoding' become HAMT sharded; scripts that worked on plain directories using the deprecated object/patch add-link RPC start failing after re-sharding the directory.

Related errors


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