ipfs/kubo · error

%q points below a root CID, expected a single CID

Error message

%q points below a root CID, expected a single CID

What it means

CidFromArg accepts an argument that must resolve to a single root CID (e.g. /ipfs/<cid> or ipfs://<cid>). If the parsed immutable path has more than two segments, it points below a root (e.g. /ipfs/<cid>/sub/path), which is not a single CID, so this error is returned. Note this check happens after root resolution, so /ipns paths with subsegments fail on root resolution first.

Source

Thrown at core/commands/cmdutils/utils.go:114

func CidFromArg(arg string) (cid.Cid, error) {
	// Fast path: a bare CID with no scheme or path components.
	if c, err := cid.Decode(arg); err == nil {
		return c, nil
	}

	p, err := PathOrCidPath(arg)
	if err != nil {
		return cid.Undef, err
	}

	imm, err := path.NewImmutablePath(p)
	if err != nil {
		// A mutable path (e.g. /ipns/name) has no static root CID.
		return cid.Undef, err
	}

	if len(imm.Segments()) > 2 {
		return cid.Undef, fmt.Errorf("%q points below a root CID, expected a single CID", arg)
	}

	return imm.RootCid(), nil
}

// CloneAddrInfo returns a copy of the AddrInfo with a cloned Addrs slice.
// This prevents data races if the sender reuses the backing array.
// See: https://github.com/ipfs/kubo/issues/11116
func CloneAddrInfo(ai peer.AddrInfo) peer.AddrInfo {
	return peer.AddrInfo{
		ID:    ai.ID,
		Addrs: slices.Clone(ai.Addrs),
	}
}

View on GitHub (pinned to 329838acdf)

Solutions

  1. Strip the subpath and pass only the root: /ipfs/<cid> or ipfs://<cid>
  2. Resolve the child path first (ipfs resolve) if you need the CID of the nested item, then pass that CID alone
  3. Validate arguments in scripts before invoking CID-only commands

Example fix

// before
ipfs pin remote add /ipfs/bafy.../images/logo.png
// after
ipfs pin remote add /ipfs/bafy...   # or resolve the nested path to its own CID first
Defensive patterns

Strategy: validation

Validate before calling

p, err := path.NewPath(arg)
if err != nil {
    return err
}
imm, err := p.ImmutablePath(ctx)
if err != nil {
    return err
}
if len(imm.Segments()) > 2 {
    return fmt.Errorf("%s must be a bare CID path", arg)
}

Type guard

func isBareCIDPath(arg string) bool {
    p, err := path.NewPath(arg)
    if err != nil {
        return false
    }
    return len(strings.Split(strings.Trim(p.String(), "/"), "/")) <= 2
}

Try / catch

c, err := cmdutils.CidFromArg(ctx, api, arg)
if err != nil {
    if strings.Contains(err.Error(), "points below a root CID") {
        return fmt.Errorf("pass only the root CID, not a subpath: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Passing a path with a subpath — `ipfs pin remote ls` / listByArgs with 'ipfs://<cid>/child' or '/ipfs/<cid>/foo' — to commands that expect exactly one CID argument.

Common situations: Copy-pasting gateway URLs (which contain subpaths) into CID-only commands; scripting with paths built from content listings that include nested segments.

Related errors


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