ipfs/kubo · error

unrecognized fsn type: %#v

Error message

unrecognized fsn type: %#v

What it means

Adder's output handling dispatches on the type of an fsn (filesystem node) entry collected during a UnixFS add operation. When outputDirs/outputDagnode encounters an fsn value whose concrete type is neither a directory nor a recognized node kind, it fails with this error including the value formatted with %#v. It indicates an internal dispatch gap: a files.Node implementation that coreunix does not know how to serialize.

Source

Thrown at core/coreunix/add.go:265

				return err
			}

			childpath := gopath.Join(path, name)
			err = adder.outputDirs(childpath, child)
			if err != nil {
				return err
			}

			fsn.Uncache(name)
		}
		nd, err := fsn.GetNode()
		if err != nil {
			return err
		}

		return outputDagnode(adder.Out, path, nd)
	default:
		return fmt.Errorf("unrecognized fsn type: %#v", fsn)
	}
}

func (adder *Adder) addNode(node ipld.Node, path string) error {
	// patch it into the root
	if path == "" {
		path = node.Cid().String()
	}

	if pi, ok := node.(*posinfo.FilestoreNode); ok {
		node = pi.Node
	}

	mr, err := adder.mfsRoot()
	if err != nil {
		return err
	}

View on GitHub (pinned to 329838acdf)

Solutions

  1. Pass only standard files types: files.NewBytesFile, files.NewMapFile, files.NewSliceFile, files.NewSerialFile, files.NewSymlinkFile
  2. Check that all files imports come from a single consistent package path (matching the kubo go-libipfs/files version)
  3. Update kubo/coreunix and go-libipfs to compatible versions so type switches recognize your node types
  4. If you truly need custom node kinds, convert them to a supported type (directory map, slice, or file) before adding

Example fix

// before: custom node unknown to the switch
type myNode struct{ files.Node }
adder.AddAllAndPin(ctx, myNode{}...)  // unrecognized fsn type
// after: convert to a supported type
entry, _ := files.NewBytesFile(data)
iter := files.NewSliceFile("", "", []files.Node{entry})
adder.AddAllAndPin(ctx, iter, false)
Defensive patterns

Strategy: type-guard

Validate before calling

switch n.(type) {
case files.File, *files.Symlink, files.Directory:
	// ok
default:
	return fmt.Errorf("unsupported node type %T", n)
}

Type guard

func isKnownFsn(n files.Node) bool {
	switch n.(type) {
	case files.File, *files.Symlink, files.Directory:
		return true
	default:
		return false
	}
}

Try / catch

if err := adder.AddAllAndPin(ctx, node, false); err != nil {
	if strings.Contains(err.Error(), "unrecognized fsn type") {
		return fmt.Errorf("convert node %T to a supported files kind", node)
	}
	return err
}

Prevention

When it happens

Trigger: Calling Adder.AddAllAndPin / Add with an files.Node implementation that is not files.File, files.Directory, or files.Symlink (e.g. a custom files.Node type implementing the interface but not one of the known concrete kinds), typically via files.NewMapFile or a wrapped custom node.

Common situations: Custom importer code wrapping or substituting files.Node types; passing a files.Node whose concrete type changed after a go-ipfs-files library version upgrade; mixing old import paths (github.com/ipfs/go-ipfs/files vs github.com/ipfs/go-libipfs/files) so type switches no longer match.

Related errors


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