ipfs/kubo · error

querying orphaned keystore data: %w

Error message

querying orphaned keystore data: %w

What it means

purgeOrphanedKeystoreData runs a keys-only Query over the datastore with the orphaned-prefix to find keystore entries that no longer belong to any mounted keystore, then batches deletes for them. This error wraps a failure returned by ds.Query itself, meaning the sweep never started — the underlying datastore refused or failed the query. The deferred results.Close() and iteration never happen, so no data was deleted.

Source

Thrown at core/node/provider.go:552

const purgeBatchSize = 1 << 12 // 4096

// purgeOrphanedKeystoreData deletes all keys under /provider/keystore/ from the
// shared repo datastore. These were written by older Kubo versions that stored
// provider keystore data inline in the shared datastore. The new code uses
// separate filesystem datastores under <repo>/{KeystoreDatastorePath}/ instead.
//
// The operation is idempotent and safe to interrupt: partial completion is
// fine because already-deleted keys are no-ops on re-run.
func purgeOrphanedKeystoreData(ctx context.Context, ds datastore.Batching) error {
	orphanedPrefix := providerDatastoreKey.Child(keystoreDatastoreKey).String()
	syncKey := datastore.NewKey(orphanedPrefix)

	results, err := ds.Query(ctx, query.Query{
		Prefix:   orphanedPrefix,
		KeysOnly: true,
	})
	if err != nil {
		return fmt.Errorf("querying orphaned keystore data: %w", err)
	}
	defer results.Close()

	var batch datastore.Batch
	var count, pending int
	for result := range results.Next() {
		if ctx.Err() != nil {
			return ctx.Err()
		}
		if result.Error != nil {
			return fmt.Errorf("iterating orphaned keystore data: %w", result.Error)
		}
		if batch == nil {
			batch, err = ds.Batch(ctx)
			if err != nil {
				return fmt.Errorf("creating batch for orphaned keystore cleanup: %w", err)
			}
		}

View on GitHub (pinned to 329838acdf)

Solutions

  1. Inspect the wrapped cause at the end of the chain — it identifies which datastore and why (I/O error, not open, etc.).
  2. Check permissions and disk space/free inodes on the repo directory containing the keystore datastores.
  3. Stop the node, run datastore integrity checks (e.g. flatfs verify, leveldb recovery), and restart.
  4. If the keystore datastore directory was deleted externally, restore it from backup or re-create it via MountKeystoreDatastores.
  5. Retry the purge after fixing the underlying datastore; the error is pre-delete, so it is safe to rerun.

Example fix

// before (purge on possibly-closed datastore)
results, err := ds.Query(ctx, query.Query{Prefix: orphanedPrefix, KeysOnly: true})
if err != nil {
    return fmt.Errorf("querying orphaned keystore data: %w", err)
}
// after (caller-side guard)
if err := pingDatastore(ctx, ds); err != nil { // health check before purge
    return fmt.Errorf("skipping orphan purge, datastore unhealthy: %w", err)
}
results, err := ds.Query(ctx, query.Query{Prefix: orphanedPrefix, KeysOnly: true})
if err != nil {
    return fmt.Errorf("querying orphaned keystore data: %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

// Before the purge, confirm the datastore answers a trivial query:
probe, err := ds.Query(ctx, query.Query{Prefix: orphanedPrefix, KeysOnly: true, Limit: 1})
if err != nil {
    return fmt.Errorf("datastore unhealthy, aborting purge: %w", err)
}
probe.Close()

Try / catch

results, err := ds.Query(ctx, query.Query{Prefix: orphanedPrefix, KeysOnly: true})
if err != nil {
    if ctx.Err() != nil {
        return fmt.Errorf("purge canceled: %w", ctx.Err())
    }
    // transient I/O problems justify one bounded retry; nothing was deleted
    return retryPurge(ctx, ds, 1)
}

Prevention

When it happens

Trigger: Calling purgeOrphanedKeystoreData when ds.Query(ctx, query.Query{Prefix: orphanedPrefix, KeysOnly: true}) errors — e.g. the mounted datastore is closed/unavailable, the underlying flatfs/levelds directory is unreadable or corrupted, or the query was rejected by a datastore that does not support prefix queries in its current state.

Common situations: Disk I/O errors or a full disk under the repo directory; keystore datastore directory deleted or permission-changed while the node runs; running the purge against a datastore implementation with query limitations; corrupted keystore database after an unclean shutdown.

Related errors


AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03). Data as JSON: /api/errors/850406b5a645ff6f. Report an issue: GitHub.