{"record":{"id":"08394dfd2faf9d2a","repo":"ipfs/kubo","slug":"http-api-returned-no-error-and-no-results","errorCode":null,"errorMessage":"http api returned no error and no results","messagePattern":"http api returned no error and no results","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"client/rpc/pin.go","lineNumber":135,"sourceCode":"\t}\n\tvar out pinRefKeyList\n\terr = api.core().Request(\"pin/ls\").\n\t\tOption(\"type\", options.WithType).\n\t\tOption(\"arg\", p.String()).\n\t\tExec(ctx, &out)\n\tif err != nil {\n\t\t// TODO: This error-type discrimination based on sub-string matching is brittle.\n\t\t// It is addressed by this open issue: https://github.com/ipfs/go-ipfs/issues/7563\n\t\tif strings.Contains(err.Error(), \"is not pinned\") {\n\t\t\treturn \"\", false, nil\n\t\t}\n\t\treturn \"\", false, err\n\t}\n\n\tfor _, obj := range out.Keys {\n\t\treturn obj.Type, true, nil\n\t}\n\treturn \"\", false, errors.New(\"http api returned no error and no results\")\n}\n\nfunc (api *PinAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.PinRmOption) error {\n\toptions, err := caopts.PinRmOptions(opts...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn api.core().Request(\"pin/rm\", p.String()).\n\t\tOption(\"recursive\", options.Recursive).\n\t\tExec(ctx, nil)\n}\n\nfunc (api *PinAPI) Update(ctx context.Context, from path.Path, to path.Path, opts ...caopts.PinUpdateOption) error {\n\toptions, err := caopts.PinUpdateOptions(opts...)\n\tif err != nil {\n\t\treturn err\n\t}","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/ipfs/kubo/blob/329838acdfafae224582930457efe80aa217afc0/client/rpc/pin.go#L117-L153","documentation":"IsPinned expects the pin/ls response to contain at least one Keys entry for the queried path; an empty list with a successful HTTP status means the daemon neither reported the pin status nor an error, so the client raises this internal-consistency error instead of returning a false answer.","triggerScenarios":"api.Pin().IsPinned(ctx, p) against a daemon whose pin/ls response for the path comes back empty — typically a daemon/client version mismatch where the response field moved or was renamed, or a proxy returning 200 with an empty body.","commonSituations":"Old go-ipfs-api client against a newer kubo daemon (or vice versa), an HTTP proxy/API gateway stripping or reshaping the JSON response, or pointing the client at a non-kubo endpoint that answers 200 with unrelated JSON.","solutions":["Upgrade go-ipfs-api and kubo to matching versions so the pin/ls response shape matches.","Verify the endpoint is a real kubo RPC API: curl http://<api>/api/v0/pin/ls?type=direct&arg=<cid> and inspect the raw JSON.","Check for proxies/middleware between the client and daemon that could alter the response body."],"exampleFix":"// diagnose\n// curl -X POST \"$API/api/v0/pin/ls?arg=$CID\"\n// {\"Keys\":{\"bafy...\":{\"Type\":\"recursive\"}}}  <- expected; empty Keys means version/shape mismatch","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"_, pinned, err := api.Pin().IsPinned(ctx, p)\nif err != nil {\n    if strings.Contains(err.Error(), \"no error and no results\") {\n        // version/shape mismatch: fall back to listing pins\n        pins, lerr := api.Pin().List(ctx)\n        if lerr == nil {\n            pinned = slices.ContainsFunc(pins, func(pp path.Path) bool { return pp.String() == p.String() })\n        }\n    } else { return err }\n}","preventionTips":["Keep go-ipfs-api and kubo versions aligned","Confirm the endpoint is a genuine kubo API with a raw curl to /api/v0/pin/ls","Remove HTTP proxies that rewrite RPC JSON bodies"],"tags":["pin","http-rpc","response-validation","version-skew"],"backgroundTag":"unexpected-rpc-response-shape","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"}