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.

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.

Appendix: 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)