{"record":{"id":"25847a7ceb60e2b7","repo":"ipfs/kubo","slug":"q-points-below-a-root-cid-expected-a-single-cid","errorCode":null,"errorMessage":"%q points below a root CID, expected a single CID","messagePattern":"%q points below a root CID, expected a single CID","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/commands/cmdutils/utils.go","lineNumber":114,"sourceCode":"func CidFromArg(arg string) (cid.Cid, error) {\n\t// Fast path: a bare CID with no scheme or path components.\n\tif c, err := cid.Decode(arg); err == nil {\n\t\treturn c, nil\n\t}\n\n\tp, err := PathOrCidPath(arg)\n\tif err != nil {\n\t\treturn cid.Undef, err\n\t}\n\n\timm, err := path.NewImmutablePath(p)\n\tif err != nil {\n\t\t// A mutable path (e.g. /ipns/name) has no static root CID.\n\t\treturn cid.Undef, err\n\t}\n\n\tif len(imm.Segments()) > 2 {\n\t\treturn cid.Undef, fmt.Errorf(\"%q points below a root CID, expected a single CID\", arg)\n\t}\n\n\treturn imm.RootCid(), nil\n}\n\n// CloneAddrInfo returns a copy of the AddrInfo with a cloned Addrs slice.\n// This prevents data races if the sender reuses the backing array.\n// See: https://github.com/ipfs/kubo/issues/11116\nfunc CloneAddrInfo(ai peer.AddrInfo) peer.AddrInfo {\n\treturn peer.AddrInfo{\n\t\tID:    ai.ID,\n\t\tAddrs: slices.Clone(ai.Addrs),\n\t}\n}\n","sourceCodeStart":96,"sourceCodeEnd":129,"githubUrl":"https://github.com/ipfs/kubo/blob/329838acdfafae224582930457efe80aa217afc0/core/commands/cmdutils/utils.go#L96-L129","documentation":"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.","triggerScenarios":"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.","commonSituations":"Copy-pasting gateway URLs (which contain subpaths) into CID-only commands; scripting with paths built from content listings that include nested segments.","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"],"exampleFix":"// before\nipfs pin remote add /ipfs/bafy.../images/logo.png\n// after\nipfs pin remote add /ipfs/bafy...   # or resolve the nested path to its own CID first","handlingStrategy":"validation","validationCode":"p, err := path.NewPath(arg)\nif err != nil {\n    return err\n}\nimm, err := p.ImmutablePath(ctx)\nif err != nil {\n    return err\n}\nif len(imm.Segments()) > 2 {\n    return fmt.Errorf(\"%s must be a bare CID path\", arg)\n}","typeGuard":"func isBareCIDPath(arg string) bool {\n    p, err := path.NewPath(arg)\n    if err != nil {\n        return false\n    }\n    return len(strings.Split(strings.Trim(p.String(), \"/\"), \"/\")) <= 2\n}","tryCatchPattern":"c, err := cmdutils.CidFromArg(ctx, api, arg)\nif err != nil {\n    if strings.Contains(err.Error(), \"points below a root CID\") {\n        return fmt.Errorf(\"pass only the root CID, not a subpath: %w\", err)\n    }\n    return err\n}","preventionTips":["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"],"tags":["cid","path","arguments"],"backgroundTag":"path-below-root-cid","analyzedSha":"329838acdfafae224582930457efe80aa217afc0","analyzedAt":"2026-09-03T18:30:52.135Z","contentChangedAt":"2026-09-03T18:30:52.135Z","schemaVersion":2},"datasetVersion":"2026-09-11T00:17:11.886Z"}