ipfs/kubo · error

%w: %v

Error message

%w: %v

What it means

The source CID is dag-pb but the dag-pb block's embedded UnixFS data failed to parse (ft.FSNodeFromBytes error), so it is not a valid UnixFS node. The error message renders as "cp: source must be a valid UnixFS (dag-pb or raw codec): <parse error>" — the %w wraps errFilesCpInvalidUnixFS so errors.Is against it still matches.

Source

Thrown at core/commands/files.go:562

		node, err := getNodeFromPath(req.Context, nd, api, src)
		if err != nil {
			return fmt.Errorf("cp: cannot get node from path %s: %s", src, err)
		}

		// Sanity-check: ensure root CID is a valid UnixFS (dag-pb or raw block)
		// Context: https://github.com/ipfs/kubo/issues/10331
		srcCidType := node.Cid().Type()
		switch srcCidType {
		case cid.Raw:
			if _, ok := node.(*dag.RawNode); !ok {
				return errFilesCpInvalidUnixFS
			}
		case cid.DagProtobuf:
			if _, ok := node.(*dag.ProtoNode); !ok {
				return errFilesCpInvalidUnixFS
			}
			if _, err = ft.FSNodeFromBytes(node.(*dag.ProtoNode).Data()); err != nil {
				return fmt.Errorf("%w: %v", errFilesCpInvalidUnixFS, err)
			}
		default:
			return errFilesCpInvalidUnixFS
		}

		mkParents, _ := req.Options[filesParentsOptionName].(bool)
		if mkParents {
			maxDirLinks := int(cfg.Import.UnixFSDirectoryMaxLinks.WithDefault(config.DefaultUnixFSDirectoryMaxLinks))
			sizeEstimationMode := cfg.Import.HAMTSizeEstimationMode()
			err := ensureContainingDirectoryExists(nd.FilesRoot, dst,
				mfs.WithCidBuilder(prefix),
				mfs.WithMaxLinks(maxDirLinks),
				mfs.WithSizeEstimationMode(sizeEstimationMode),
			)
			if err != nil {
				return err
			}
		}

View on GitHub (pinned to 329838acdf)

Solutions

  1. Confirm the block is real UnixFS: `ipfs dag get <cid> | head` or `ipfs ls /ipfs/<cid>` (ls works only on UnixFS)
  2. Re-add the original bytes with `ipfs add` to get a proper UnixFS dag-pb node
  3. If the content is a raw dag-pb IPLD document, it cannot be placed in MFS; export and re-add as a file
  4. Use `ipfs files cp` only with CIDs produced by `ipfs add` or raw blocks

Example fix

// before: dag-put output copied into MFS
ipfs dag put --store-codec dag-pb data.pb
ipfs files cp /ipfs/<cid> /my-file  // fails

// after
ipfs add -q data
ipfs files cp /ipfs/<new-cid> /my-file
Defensive patterns

Strategy: validation

Validate before calling

// dag-pb CIDs must come from ipfs add (UnixFS), not dag put
if isDagPbButFromDagPut(cid) {
    return fmt.Errorf("re-add content with `ipfs add` before files cp")
}

Type guard

func isValidUnixFSDagPb(cid string) bool {
    // `ipfs ls` succeeds only on UnixFS dag-pb nodes
    return run("ipfs", "ls", "/ipfs/"+cid) == nil
}

Try / catch

if err := ipfsFilesCp(src, dst); err != nil {
    if errors.Is(err, errFilesCpInvalidUnixFS) {
        // export original bytes and re-add with `ipfs add`
    }
}

Prevention

When it happens

Trigger: Running `ipfs files cp /ipfs/<cid> /dst` where <cid> is dag-pb but its protobuf data is not a valid UnixFS FSNode — e.g. a bare dag-pb IPLD document that was created with `ipfs dag put` (no unixfs encoding) rather than `ipfs add`.

Common situations: Putting arbitrary protobuf data with `ipfs dag put --store-codec dag-pb` and then trying to cp it into MFS; corrupted dag-pb blocks; hand-crafted dag-pb documents without UnixFS Data field.

Related errors


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