ipfs/kubo · error

expected at least one child dir, got none

Error message

expected at least one child dir, got none

What it means

When AddAllAndPin finishes importing a root that is a directory, it tries to unwrap a single-child root so the final CID addresses the child directly (flattening redundant single-entry directory wrappers). If ListNames on the root directory returns zero children, it errors instead of producing a CID for an empty directory wrapper it cannot flatten. In practice this surfaces when the root directory contains no entries at all.

Source

Thrown at core/coreunix/add.go:345

	root = rootdir

	err = root.Flush()
	if err != nil {
		return nil, err
	}

	// if adding a file without wrapping, swap the root to it (when adding a
	// directory, mfs root is the directory)
	_, dir := file.(files.Directory)
	var name string
	if !dir {
		children, err := rootdir.ListNames(adder.ctx)
		if err != nil {
			return nil, err
		}

		if len(children) == 0 {
			return nil, fmt.Errorf("expected at least one child dir, got none")
		}

		// Replace root with the first child
		name = children[0]
		root, err = rootdir.Child(name)
		if err != nil {
			return nil, err
		}
	}

	err = mr.Close()
	if err != nil {
		return nil, err
	}

	nd, err := root.GetNode()
	if err != nil {
		return nil, err

View on GitHub (pinned to 329838acdf)

Solutions

  1. Add at least one entry to the directory root before calling AddAllAndPin
  2. If you intentionally want an empty-directory CID, use a different API path (e.g. construct the UnixFS dir node directly or use files/MFS APIs) rather than AddAllAndPin
  3. Check hidden-file filters (.hide options) that may be excluding every entry
  4. Verify the source directory passed to files.NewSerialFile is not empty

Example fix

// before: empty root
empty := files.NewMapFile("", "", map[string]files.Node{})
adder.AddAllAndPin(ctx, empty, true) // expected at least one child dir, got none
// after: include at least one child
entry := files.NewBytesFile([]byte("hello"))
root := files.NewMapFile("", "", map[string]files.Node{"hello.txt": entry})
adder.AddAllAndPin(ctx, root, true)
Defensive patterns

Strategy: validation

Validate before calling

names, err := rootdir.ListNames(ctx)
if err != nil { return err }
if len(names) == 0 {
	return errors.New("refusing to AddAllAndPin an empty directory root")
}

Try / catch

if err := adder.AddAllAndPin(ctx, root, true); err != nil {
	if strings.Contains(err.Error(), "expected at least one child dir") {
		// fall back to constructing an empty-dir UnixFS node directly
	}
	return err
}

Prevention

When it happens

Trigger: Calling Adder.AddAllAndPin on a files.Directory root that ends up with no named children — e.g. files.NewMapFile("", "", map[string]files.Node{}) or a SerialFile walk over an empty directory — where the flattening path ListNames returns an empty list.

Common situations: Importing an empty directory via ipfs add -r; constructing map/slice file roots programmatically and forgetting to add entries; filtering out all entries (e.g. hidden-file filters with everything excluded) before adding.

Related errors


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