ipfs/kubo · critical
serveHTTPGateway: ConstructNode() failed: %s
Error message
serveHTTPGateway: ConstructNode() failed: %s
What it means
serveHTTPGateway builds the full IPFS node via cctx.ConstructNode() before serving gateway requests. Any error constructing the node (repo lock, datastore open, blockstore init, p2p host setup) is wrapped with this message and daemon startup aborts.
Source
Thrown at cmd/ipfs/kubo/daemon.go:1134
corehttp.VersionOption(),
corehttp.CheckVersionOption(),
}
if cfg.Experimental.P2pHttpProxy {
opts = append(opts, corehttp.P2PProxyOption())
}
if cfg.Gateway.ExposeRoutingAPI.WithDefault(config.DefaultExposeRoutingAPI) {
opts = append(opts, corehttp.RoutingOption())
}
if len(cfg.Gateway.RootRedirect) > 0 {
opts = append(opts, corehttp.RedirectOption("", cfg.Gateway.RootRedirect))
}
node, err := cctx.ConstructNode()
if err != nil {
return nil, fmt.Errorf("serveHTTPGateway: ConstructNode() failed: %s", err)
}
// Buffer channel to prevent deadlock when multiple servers write errors simultaneously
errc := make(chan error, len(listeners))
var wg sync.WaitGroup
// Start all servers and wait for them to be ready before writing gateway file.
// This prevents race conditions where external tools (like systemd path units)
// see the file and try to connect before servers can accept connections.
if len(listeners) > 0 {
readyChannels := make([]chan struct{}, len(listeners))
for i, lis := range listeners {
readyChannels[i] = make(chan struct{})
ready := readyChannels[i]
wg.Go(func() {
errc <- corehttp.ServeWithReady(node, manet.NetListener(lis), ready, opts...)
})
}View on GitHub (pinned to 329838acdf)
Solutions
- Check for and stop an already-running daemon holding repo.lock: pkill -f "ipfs daemon", or remove a stale $IPFS_PATH/repo.lock if no daemon is running.
- Run `ipfs repo fsck` / inspect datastore errors in the wrapped message; restore from backup if the datastore is corrupted.
- Validate config changes with `ipfs config show` (especially Datastore.* and Experimental.* keys) and revert bad edits.
- Fix repo directory permissions/disk space so the datastore can be opened read-write.
Example fix
// before $ ipfs daemon & ipfs daemon ConstructNode() failed: lock: someone already has the lock // after $ pkill -f "ipfs daemon" $ rm -f $IPFS_PATH/repo.lock # only if no daemon runs $ ipfs daemon
Defensive patterns
Strategy: validation
Validate before calling
if [ -f "$IPFS_PATH/repo.lock" ] && ! pgrep -f 'ipfs daemon' >/dev/null; then echo 'stale lock, no daemon running'; rm -f "$IPFS_PATH/repo.lock" fi
Try / catch
node, err := cctx.ConstructNode()
if err != nil {
if strings.Contains(err.Error(), "lock") {
log.Fatal("another daemon holds repo.lock; stop it first")
}
log.Fatalf("node construction failed: %v", err)
} Prevention
- One daemon per repo; use pkill or `ipfs shutdown` before restarting.
- Let the daemon shut down gracefully so locks are released.
- Test datastore config changes in a copy of the repo first.
- Monitor disk space and repo permissions in deployment.
When it happens
Trigger: cctx.ConstructNode() returns an error: repo already locked by another daemon, datastore corruption or unsupported type, bad Datastore config, key/keystore problems, failure initializing libp2p services.
Common situations: Two daemons on the same IPFS_PATH (repo.lock held); corrupted flatfs/badgerds datastore after crash; bad Experimental flags or Datastore.Spec changes; insufficient disk or bad ownership of the repo.
Related errors
- mountFuse: ConstructNode() failed: %s
- ipfs api address could not be found
- n.Err (server-provided bad-node error message)
- cannot get migrations from unknown fetcher type
- nothing downloaded by ipfs fetcher
AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03).
Data as JSON: /api/errors/2bdf636055388ba7.
Report an issue: GitHub.