ipfs/kubo · critical
serveHTTPGatewayOverLibp2p: ConstructNode() failed: %s
Error message
serveHTTPGatewayOverLibp2p: ConstructNode() failed: %s
What it means
serveTrustlessGatewayOverLibp2p serves the trustless gateway over a libp2p stream handler (/ipfs/gateway protocol). It constructs the node first, and any error from cctx.ConstructNode() is wrapped with this message (note the message says serveHTTPGatewayOverLibp2p for historical reasons). This only runs when Experimental.GatewayOverLibp2p is enabled.
Source
Thrown at cmd/ipfs/kubo/daemon.go:1186
if err := node.Repo.SetGatewayAddr(addr); err != nil {
return nil, fmt.Errorf("serveHTTPGateway: SetGatewayAddr() failed: %w", err)
}
}
go func() {
wg.Wait()
close(errc)
}()
return errc, nil
}
const gatewayProtocolID protocol.ID = "/ipfs/gateway" // FIXME: specify https://github.com/ipfs/specs/issues/433
func serveTrustlessGatewayOverLibp2p(cctx *oldcmds.Context) (<-chan error, error) {
node, err := cctx.ConstructNode()
if err != nil {
return nil, fmt.Errorf("serveHTTPGatewayOverLibp2p: ConstructNode() failed: %s", err)
}
cfg, err := node.Repo.Config()
if err != nil {
return nil, fmt.Errorf("could not read config: %w", err)
}
if !cfg.Experimental.GatewayOverLibp2p {
errCh := make(chan error)
close(errCh)
return errCh, nil
}
opts := []corehttp.ServeOption{
corehttp.MetricsCollectionOption("libp2p-gateway"),
corehttp.Libp2pGatewayOption(),
corehttp.VersionOption(),
}
View on GitHub (pinned to 329838acdf)
Solutions
- Inspect the inner error after the prefix; it names the construction failure (lock, datastore, identity).
- Stop the competing daemon or remove a stale repo.lock when no daemon runs.
- Validate the identity and swarm config: `ipfs config Identity.PeerID` and `ipfs config Addresses.Swarm`.
- If you do not need trustless-over-libp2p, disable it: `ipfs config --json Experimental.GatewayOverLibp2p false`.
Example fix
// before $ ipfs config --json Experimental.GatewayOverLibp2p true && ipfs daemon # fails with lock held // after $ pkill -f "ipfs daemon" && ipfs daemon
Defensive patterns
Strategy: validation
Validate before calling
if enabled, _ := ipfsConfig.Get("Experimental.GatewayOverLibp2p"); enabled == true {
if _, err := os.Stat(filepath.Join(ipfsPath, "repo.lock")); err == nil && daemonRunning() {
return errors.New("repo locked by a running daemon")
}
} Try / catch
node, err := cctx.ConstructNode()
if err != nil {
if strings.Contains(err.Error(), "lock") {
log.Fatal("stop the other daemon using this IPFS_PATH")
}
log.Fatalf("ConstructNode for libp2p gateway failed: %v", err)
} Prevention
- Never start two daemons on the same IPFS_PATH.
- Validate identity/swarm config before enabling Experimental.GatewayOverLibp2p.
- Keep the experimental flag off unless trustless-over-libp2p is needed.
- Clean stale repo.lock after abnormal exits.
When it happens
Trigger: cctx.ConstructNode() fails while Experimental.GatewayOverLibp2p is true: repo lock held, datastore open failure, libp2p host/identity issues, bad keystore or p2p config.
Common situations: Same repo used by two daemons (repo.lock); corrupted datastore; invalid identity key; enabling Experimental.GatewayOverLibp2p on a config with an unusable swarm setup.
Related errors
- serveHTTPApi: ConstructNode() failed: %s
- serveHTTPGateway: GetConfig() failed: %s
- serveHTTPGateway: socket activation failed: %s
- serveHTTPGateway: invalid gateway address: %q (err: %s)
- serveHTTPGateway: manet.Listen(%s) failed: %s
AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03).
Data as JSON: /api/errors/74a3251a433dc1b1.
Report an issue: GitHub.