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
- Strip the subpath and pass only the root: /ipfs/<cid> or ipfs://<cid>
- Resolve the child path first (ipfs resolve) if you need the CID of the nested item, then pass that CID alone
- 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
- Strip subpaths from gateway URLs before passing to CID-only commands
- Use `ipfs resolve <path>` to obtain a CID when you have a nested path
- Validate argument shape in wrapper scripts
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
- %s key is not a map
- %s not found
- Import.CidVersion must be 0 or 1, got %d
- inline-limit %d exceeds maximum allowed size of %d bytes
- %s: MFS destination %q is not a directory
AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03).
Data as JSON: /api/errors/25847a7ceb60e2b7.
Report an issue: GitHub.