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

  1. 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.
  2. Run `ipfs repo fsck` / inspect datastore errors in the wrapped message; restore from backup if the datastore is corrupted.
  3. Validate config changes with `ipfs config show` (especially Datastore.* and Experimental.* keys) and revert bad edits.
  4. 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

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


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