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

  1. Inspect the inner error after the prefix; it names the construction failure (lock, datastore, identity).
  2. Stop the competing daemon or remove a stale repo.lock when no daemon runs.
  3. Validate the identity and swarm config: `ipfs config Identity.PeerID` and `ipfs config Addresses.Swarm`.
  4. 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

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


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