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 goroutineView on GitHub (pinned to 329838acdf)
Solutions
- 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.
- Verify with `ipfs block stat <cid>` that the block exists locally.
- If you only want the CID discoverable, download and pin the content on this node.
- 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
- Only call Provide on CIDs your node has stored or pinned
- Check `ipfs block stat <cid>` (or blockstore.Has) before providing
- Remember GC can remove blocks: pin anything you intend to keep announcing
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
- pin check failed: %w
- supernode routing was never fully implemented and has been r
- Routing.AcceleratedDHTClient option is set even tho Routing.
- unrecognized routing option: %s
- invalid key
AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03).
Data as JSON: /api/errors/8784105675db30f3.
Report an issue: GitHub.