{"record":{"id":"89091b607f5511e4","repo":"ipfs/kubo","slug":"ls-returned-more-objects-than-expected-d","errorCode":null,"errorMessage":"ls returned more objects than expected (%d)","messagePattern":"ls returned more objects than expected \\((.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/rpc/apifile.go","lineNumber":223,"sourceCode":"\treturn it.cur.Name\n}\n\nfunc (it *apiIter) Next() bool {\n\tif it.ctx.Err() != nil {\n\t\tit.err = it.ctx.Err()\n\t\treturn false\n\t}\n\n\tvar out lsOutput\n\tif err := it.dec.Decode(&out); err != nil {\n\t\tif err != io.EOF {\n\t\t\tit.err = err\n\t\t}\n\t\treturn false\n\t}\n\n\tif len(out.Objects) != 1 {\n\t\tit.err = fmt.Errorf(\"ls returned more objects than expected (%d)\", len(out.Objects))\n\t\treturn false\n\t}\n\n\tif len(out.Objects[0].Links) != 1 {\n\t\tit.err = fmt.Errorf(\"ls returned more links than expected (%d)\", len(out.Objects[0].Links))\n\t\treturn false\n\t}\n\n\tit.cur = out.Objects[0].Links[0]\n\tc, err := cid.Parse(it.cur.Hash)\n\tif err != nil {\n\t\tit.err = err\n\t\treturn false\n\t}\n\n\tswitch it.cur.Type {\n\tcase unixfs.THAMTShard, unixfs.TMetadata, unixfs.TDirectory:\n\t\tit.curFile, err = it.core.getDir(it.ctx, path.FromCid(c), int64(it.cur.Size), it.cur.Mode, it.cur.ModTime)","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/ipfs/kubo/blob/329838acdfafae224582930457efe80aa217afc0/client/rpc/apifile.go#L205-L241","documentation":"The apiIter drives a paged 'ls' RPC where each page is expected to contain exactly one object with one link per entry. If the response contains len(out.Objects) != 1, the iterator records this error and stops, protecting the caller from silently misinterpreting a multi-object page as a single directory entry. It signals a contract violation by the server.","triggerScenarios":"Iterating a UnixfsAPI directory (Get->directory / ls iteration) when the daemon returns an ls page with zero or multiple objects — e.g. server behavior drift, proxy aggregation, or a response shaped by a non-kubo server.","commonSituations":"Mixed client/daemon versions where ls output batching changed; middleware (caching proxies) merging ls responses; implementing the API surface with a custom server that returns multiple objects per request.","solutions":["Use matching kubo versions for client and daemon","Bypass proxies/middleware that may batch or transform /api/v0/ls responses","Verify with `curl -X POST http://127.0.0.1:5001/api/v0/ls?arg=<path>` that one object per response is returned","If you need multi-entry listing, consume the standard ls RPC yourself instead of this single-entry iterator"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// verify server shape directly before iterating\nvar out struct{ Objects []struct{} `json:\"Objects\"` }\n_ = api.Request(\"ls\").Option(\"arg\", p).Exec(ctx, &out)\nif len(out.Objects) != 1 { return fmt.Errorf(\"server returns non-single-object ls pages\") }","typeGuard":null,"tryCatchPattern":"it, err := api.Unixfs().Get(ctx, p)\n// iterate; if Next fails with the count error, retry against direct daemon\nif strings.Contains(err.Error(), \"ls returned more objects than expected\") {\n    return retryDirect(ctx, p) // bypass proxies\n}","preventionTips":["Do not place transforming proxies in front of /api/v0/ls","Pin client and daemon to matching versions","Consume the ls RPC directly for bulk listings"],"tags":["go","ipfs","rpc","ls","invariant"],"backgroundTag":"ls-response-shape-mismatch","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"}