ipfs/kubo · error

provider: error flushing MFS

Error message

provider: error flushing MFS: %w

What it means

Returned by mfsWalkProvider (the +unique/+entities MFS provider) when mfsRoot.FlushMemFree(ctx) fails. FlushMemFree flushes MFS writes to the blockstore and frees memory; any datastore write error during that flush aborts the reprovide cycle before the DAG walk starts. The original datastore error is wrapped and preserved.

Solutions

  1. Check the wrapped error in logs: disk-full and I/O errors are the usual cause; free space or fix the disk
  2. Restart the daemon to get a fresh MFS root; the periodic reprovide retries the next cycle
  3. Verify datastore health (e.g. 'ipfs repo stat', badger check/repair utilities)
  4. If context cancellation caused it, ensure the node stays up long enough for the flush to complete
Defensive patterns

Strategy: retry

Validate before calling

// ensure datastore is writable and has space before heavy operations
usage := diskUsage(repoPath)
if usage.free < minFreeBytes {
    return fmt.Errorf("insufficient free space for MFS flush")
}

Try / catch

if err := mfsRoot.FlushMemFree(ctx); err != nil {
    if ctx.Err() != nil {
        return nil, ctx.Err() // cancellation: retry later
    }
    return nil, fmt.Errorf("provider: error flushing MFS: %w", err)
}

Prevention

When it happens

Trigger: Reprovide cycle with strategies using mfs (+unique and/or +entities modifiers) when FlushMemFree hits a datastore write error, disk full, or context cancellation during flush.

Common situations: Disk full or quota exceeded on the node's datastore, corrupted datastore after unclean shutdown, slow/remote datastore timing out, or daemon shutdown cancelling the context mid-flush.

Related errors


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

Appendix: source

Thrown at core/node/provider.go:1285

	}
	return mfsWalkProvider(mfsRoot, bs, tracker, walk)
}

// mfsEntityRootsProvider is the +entities counterpart. It walks with
// WalkEntityRoots, emitting only entity roots and skipping file chunks.
func mfsEntityRootsProvider(mfsRoot *mfs.Root, bs blockstore.Blockstore, tracker walker.VisitedTracker) provider.KeyChanFunc {
	walk := func(ctx context.Context, root cid.Cid, emit func(cid.Cid) bool, opts ...walker.Option) error {
		return walker.WalkEntityRoots(ctx, root, walker.NodeFetcherFromBlockstore(bs), emit, opts...)
	}
	return mfsWalkProvider(mfsRoot, bs, tracker, walk)
}

// mfsWalkProvider builds a KeyChanFunc that flushes MFS, then walks
// with the given walkFunc using a shared tracker and locality check.
func mfsWalkProvider(mfsRoot *mfs.Root, bs blockstore.Blockstore, tracker walker.VisitedTracker, walk walkFunc) provider.KeyChanFunc {
	return func(ctx context.Context) (<-chan cid.Cid, error) {
		if err := mfsRoot.FlushMemFree(ctx); err != nil {
			return nil, fmt.Errorf("provider: error flushing MFS: %w", err)
		}
		rootNode, err := mfsRoot.GetDirectory().GetNode()
		if err != nil {
			return nil, fmt.Errorf("provider: error loading MFS root: %w", err)
		}

		ch := make(chan cid.Cid)
		go func() {
			defer close(ch)
			locality := func(ctx context.Context, c cid.Cid) (bool, error) {
				return bs.Has(ctx, c)
			}
			_ = walk(ctx, rootNode.Cid(), func(c cid.Cid) bool {
				select {
				case ch <- c:
					return true
				case <-ctx.Done():
					return false

View on GitHub (pinned to 329838acdf)