ipfs/kubo · error

block %s not found locally, cannot provide

Error message

block %s not found locally, cannot provide

What it means

Provide announces a block's CID to the network, but only blocks actually present in the local blockstore can be provided (the provide system reads them to build announcements). The API checks blockstore.Has first and refuses with this error for foreign or unpinned CIDs. This enforces the no-silent-CID-injection rule: a node only announces content it locally holds.

Source

Thrown at core/coreapi/routing.go:148

	err = api.checkOnline(false)
	if err != nil {
		return err
	}

	rp, _, err := api.core().ResolvePath(ctx, path)
	if err != nil {
		return err
	}

	c := rp.RootCid()

	has, err := api.blockstore.Has(ctx, c)
	if err != nil {
		return err
	}

	if !has {
		return fmt.Errorf("block %s not found locally, cannot provide", c)
	}

	if settings.Recursive {
		err = provideKeysRec(ctx, api.provider, api.blockstore, []cid.Cid{c})
	} else {
		err = api.provider.StartProviding(false, c.Hash())
	}
	if err != nil {
		return err
	}

	return nil
}

func provideKeysRec(ctx context.Context, prov node.DHTProvider, bs blockstore.Blockstore, cids []cid.Cid) error {
	provided := cidutil.NewStreamingSet()

	// Error channel with buffer size 1 to avoid blocking the goroutine

View on GitHub (pinned to 329838acdf)

Solutions

  1. Fetch/store the block locally first (e.g. `ipfs get`/cat the CID, or Pin it so GC won't remove it) before calling Provide.
  2. Verify with `ipfs block stat <cid>` that the block exists locally.
  3. If you only want the CID discoverable, download and pin the content on this node.
  4. If you intended to announce for another node, do the Provide from the node that actually stores the data.

Example fix

// before
err := api.Routing().Provide(ctx, foreignCid, false) // block absent
// after
_, err := api.Unixfs().Get(ctx, p, foreignCidPath) // store it (or pin)
err = api.Routing().Provide(ctx, foreignCid, false)
Defensive patterns

Strategy: validation

Validate before calling

has, err := blockstore.Has(ctx, c)
if err != nil {
	return err
}
if !has {
	return fmt.Errorf("cannot provide %s: block not stored locally; get/pin it first", c)
}
err = api.Routing().Provide(ctx, c, recursive)

Try / catch

err := api.Routing().Provide(ctx, c, false)
if err != nil && strings.Contains(err.Error(), "not found locally") {
	// fetch the block first, then retry
	if _, gerr := api.Block().Get(ctx, c); gerr != nil {
		return gerr
	}
	err = api.Routing().Provide(ctx, c, false)
}

Prevention

When it happens

Trigger: Calling Routing().Provide (or `ipfs routing provide`) with a CID not present in the local blockstore — e.g. a CID seen on the network but never fetched, a typo'd CID, or after the block was GC'd.

Common situations: Operators trying to act as a provider for content they only reference (not stored), scripts re-providing content after a garbage collection removed it, and library users providing CIDs from another node.

Related errors


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