{"record":{"id":"9001a41608c4e180","repo":"ipfs/kubo","slug":"iterating-orphaned-keystore-data-w","errorCode":null,"errorMessage":"iterating orphaned keystore data: %w","messagePattern":"iterating orphaned keystore data: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/node/provider.go","lineNumber":563,"sourceCode":"\tsyncKey := datastore.NewKey(orphanedPrefix)\n\n\tresults, err := ds.Query(ctx, query.Query{\n\t\tPrefix:   orphanedPrefix,\n\t\tKeysOnly: true,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"querying orphaned keystore data: %w\", err)\n\t}\n\tdefer results.Close()\n\n\tvar batch datastore.Batch\n\tvar count, pending int\n\tfor result := range results.Next() {\n\t\tif ctx.Err() != nil {\n\t\t\treturn ctx.Err()\n\t\t}\n\t\tif result.Error != nil {\n\t\t\treturn fmt.Errorf(\"iterating orphaned keystore data: %w\", result.Error)\n\t\t}\n\t\tif batch == nil {\n\t\t\tbatch, err = ds.Batch(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"creating batch for orphaned keystore cleanup: %w\", err)\n\t\t\t}\n\t\t}\n\t\tif err := batch.Delete(ctx, datastore.NewKey(result.Key)); err != nil {\n\t\t\treturn fmt.Errorf(\"batch deleting orphaned key %s: %w\", result.Key, err)\n\t\t}\n\t\tcount++\n\t\tpending++\n\t\tif pending >= purgeBatchSize {\n\t\t\tif err := batch.Commit(ctx); err != nil {\n\t\t\t\treturn fmt.Errorf(\"committing orphaned keystore cleanup batch: %w\", err)\n\t\t\t}\n\t\t\tif err := ds.Sync(ctx, syncKey); err != nil {\n\t\t\t\treturn fmt.Errorf(\"syncing orphaned keystore cleanup: %w\", err)","sourceCodeStart":545,"sourceCodeEnd":581,"githubUrl":"https://github.com/ipfs/kubo/blob/329838acdfafae224582930457efe80aa217afc0/core/node/provider.go#L545-L581","documentation":"While iterating results from the orphaned-keystore query via results.Next(), a per-entry error on a result (result.Error) is wrapped as \"iterating orphaned keystore data: %w\". Unlike error 598, the query started successfully; failure happened partway through the result stream. Entries already deleted in the open batch may or may not have been committed (the batch is not yet committed at this point), so the purge is effectively partial/no-op and safe to rerun.","triggerScenarios":"purgeOrphanedKeystoreData enumerating a result set where one or more results carry result.Error — typically an I/O error reading a key from the underlying keystore datastore mid-iteration, or a context cancellation surfaced through the result stream (ctx.Err() is checked first, so this fires for genuine result errors).","commonSituations":"Failing disk sectors or NFS/network-attached repo storage dropping reads mid-scan; keystore files removed by another process during the sweep; corrupted entries in flatfs/levelds that error on read; concurrent datastore access from two processes on the same IPFS_PATH.","solutions":["Read the wrapped cause to identify the specific key/entry that failed to iterate.","Check the storage backing the repo for I/O problems (dmesg, SMART, mount health) and disk space.","Stop other processes using the same IPFS_PATH and rerun the purge — it is resumable because deletes are batched and committed only after iteration succeeds.","Run the datastore's verification/repair tool (flatfs verify, leveldb Compact/repair) on the keystore datastore.","If a specific entry is corrupt and unrecoverable, remove that backing file/database segment and rerun."],"exampleFix":"// before\nfor result := range results.Next() {\n    if result.Error != nil {\n        return fmt.Errorf(\"iterating orphaned keystore data: %w\", result.Error)\n    }\n    ...\n}\n// after (log and skip bad entries, keep sweep resumable)\nfor result := range results.Next() {\n    if result.Error != nil {\n        log.Warnw(\"skipping unreadable orphaned keystore entry\", \"error\", result.Error)\n        continue\n    }\n    ...\n}","handlingStrategy":"try-catch","validationCode":"// Check context before starting so cancellation is not misread as a result error:\nif err := ctx.Err(); err != nil {\n    return err\n}\nif err := pingDatastore(ctx, ds); err != nil {\n    return fmt.Errorf(\"datastore not readable, aborting orphan sweep: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"for result := range results.Next() {\n    if ctx.Err() != nil {\n        batchDiscard(batch) // do not commit partial deletes\n        return ctx.Err()\n    }\n    if result.Error != nil {\n        batchDiscard(batch)\n        if isTransient(result.Error) {\n            return retryPurge(ctx, ds, 1)\n        }\n        return fmt.Errorf(\"iterating orphaned keystore data: %w\", result.Error)\n    }\n    // ... normal handling\n}","preventionTips":["Discard/rollback the batch on any iteration error so no partial deletes persist","Do not share one IPFS_PATH between processes during maintenance","Check context cancellation before result errors to classify failures correctly","Use local (non-NFS) storage for the repo to avoid mid-scan read failures"],"tags":["go","datastore","iteration","io"],"backgroundTag":"datastore-iteration-failed","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"}