ipfs/kubo · warning
%s : %w
Error message
%s : %w
What it means
offlineErrWrap decorates errors from the gateway backend when the gateway runs in offline mode. If the underlying backend returns iface.ErrOffline (a required piece of content or IPNS record is not available locally and fetching is disabled), it rewrites the error as '<original message> : service unavailable' so the gateway can map it to an HTTP 503 for the client.
Source
Thrown at core/corehttp/gateway.go:206
backend, err := gateway.NewBlocksBackend(bserv,
gateway.WithValueStore(vsRouting),
gateway.WithNameSystem(nsys),
gateway.WithResolver(pathResolver),
)
if err != nil {
return nil, err
}
return &offlineGatewayErrWrapper{gwimpl: backend}, nil
}
type offlineGatewayErrWrapper struct {
gwimpl gateway.IPFSBackend
}
func offlineErrWrap(err error) error {
if errors.Is(err, iface.ErrOffline) {
return fmt.Errorf("%s : %w", err.Error(), gateway.ErrServiceUnavailable)
}
return err
}
func (o *offlineGatewayErrWrapper) Get(ctx context.Context, path path.ImmutablePath, ranges ...gateway.ByteRange) (gateway.ContentPathMetadata, *gateway.GetResponse, error) {
md, n, err := o.gwimpl.Get(ctx, path, ranges...)
err = offlineErrWrap(err)
return md, n, err
}
func (o *offlineGatewayErrWrapper) GetAll(ctx context.Context, path path.ImmutablePath) (gateway.ContentPathMetadata, files.Node, error) {
md, n, err := o.gwimpl.GetAll(ctx, path)
err = offlineErrWrap(err)
return md, n, err
}
func (o *offlineGatewayErrWrapper) GetBlock(ctx context.Context, path path.ImmutablePath) (gateway.ContentPathMetadata, files.File, error) {
md, n, err := o.gwimpl.GetBlock(ctx, path)View on GitHub (pinned to 329838acdf)
Solutions
- Preload the requested content locally: `ipfs get <cid>` or pin it (`ipfs pin add <cid>`) on the gateway node before serving.
- If the gateway should fetch on demand, disable offline mode: `ipfs config --json Gateway.NoFetch false` and restart the daemon.
- For IPNS names, publish/resolve while online once so the record is cached, or serve only DNSLink/record-backed names with records present.
- Treat the HTTP 503 on the client side as 'content not locally available' and retry after the gateway operator preloads it.
Example fix
// before: offline gateway, content missing -> 503 // Gateway.NoFetch = true; request /ipfs/<unpinned-cid> // after: preload then serve ipfs config --json Gateway.NoFetch false # or: ipfs pin add <cid> # ensure local availability
Defensive patterns
Strategy: fallback
Validate before calling
// client-side preflight for an offline gateway
hasLocal, err := hasLocally(api, cid) // e.g. `ipfs dag stat --local` or blockstore check
if err != nil { return err }
if !hasLocal {
return fmt.Errorf("gateway is offline (NoFetch=true); content %s must be pinned locally first", cid)
} Type guard
func isOfflineUnavailable(err error) bool {
// surfaced as HTTP 503 with the original message + 'service unavailable'
return errors.Is(err, gateway.ErrServiceUnavailable) ||
errors.Is(err, iface.ErrOffline)
} Try / catch
md, resp, err := backend.Get(ctx, p)
if err != nil {
if errors.Is(err, gateway.ErrServiceUnavailable) || errors.Is(err, iface.ErrOffline) {
return nil, fmt.Errorf("content unavailable offline: %w", err) // map to 503 / trigger pinning
}
return err
} Prevention
- Pin or pre-warm all content an offline gateway is expected to serve.
- Set Gateway.NoFetch=false unless you deliberately run a cache-only gateway.
- Monitor 503 rates on offline gateways as a signal of missing local content.
- For IPNS names, resolve and cache records while the node is online.
When it happens
Trigger: Requesting a path through an HTTP gateway (Get, Head, GetCAR, ResolvePath, GetAll, GetBlock) when `Gateway.NoFetch` is true (offline gateway) and the blocks or IPNS record needed to serve the path are not present in the local datastore.
Common situations: Operating a public gateway with NoFetch=true and clients requesting content that was never added or pinned locally; IPNS name resolution on an offline gateway with no cached record; trustless/CAR requests for blocks absent from the store; misconfigured gateways where operators expect fetch-on-demand but NoFetch is enabled.
Related errors
- can't put while offline: pass `--allow-offline` to store loc
- cannot specify negative resolve cache size
- error constructing namesys: %w
- cannot specify negative resolve cache size
- error constructing namesys: %w
AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03).
Data as JSON: /api/errors/898f18f1b396b466.
Report an issue: GitHub.