ipfs/kubo · info

api not running

Error message

api not running

What it means

ErrApiNotRunning is the sentinel error signaling that no Kubo daemon API is reachable at the configured API address. It is declared once in repo/repo.go and returned by fsrepo.APIAddr when the api file does not exist, so callers can distinguish "daemon not running" (expected, recoverable) from real failures via errors.Is. cmd/ipfs/kubo/start.go treats it as a non-fatal case, e.g. to start a node without a running daemon.

Source

Thrown at repo/repo.go:18

package repo

import (
	"context"
	"errors"
	"io"
	"net"

	filestore "github.com/ipfs/boxo/filestore"
	keystore "github.com/ipfs/boxo/keystore"
	rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"

	ds "github.com/ipfs/go-datastore"
	config "github.com/ipfs/kubo/config"
	ma "github.com/multiformats/go-multiaddr"
)

var ErrApiNotRunning = errors.New("api not running") //nolint

// Repo represents all persistent data of a given ipfs node.
type Repo interface {
	// Config returns the ipfs configuration file from the repo. Changes made
	// to the returned config are not automatically persisted.
	Config() (*config.Config, error)

	// Path is the repo file-system path
	Path() string

	// UserResourceOverrides returns optional user resource overrides for the
	// libp2p resource manager.
	UserResourceOverrides() (rcmgr.PartialLimitConfig, error)

	// BackupConfig creates a backup of the current configuration file using
	// the given prefix for naming.
	BackupConfig(prefix string) (string, error)

View on GitHub (pinned to 329838acdf)

Solutions

  1. Start the daemon first (`ipfs daemon`) before commands that need the API, or use offline mode where supported.
  2. Treat the error as recoverable: compare with errors.Is(err, repo.ErrApiNotRunning) and fall back to local/offline behavior, like start.go does.
  3. Verify IPFS_PATH points at the repo whose daemon is actually running.
  4. For scripts, poll APIAddr until the daemon is up instead of failing on first attempt.

Example fix

// before
apiAddr, err := fsrepo.APIAddr(cfgRoot)
if err != nil {
	return err
}
// after
apiAddr, err := fsrepo.APIAddr(cfgRoot)
if err != nil {
	if errors.Is(err, repo.ErrApiNotRunning) {
		// run offline / start the daemon
	} else {
		return err
	}
}
Defensive patterns

Strategy: type-guard

Validate before calling

// check before calling API-dependent code
apiFile := filepath.Join(os.Getenv("IPFS_PATH"), "api")
if _, err := os.Stat(apiFile); os.IsNotExist(err) {
	// daemon not running: start it or use offline mode
}
// or probe the endpoint
if _, err := http.Get("http://" + apiHost + "/api/v0/id"); err != nil { /* not running */ }

Type guard

func isAPINotRunning(err error) bool {
	return errors.Is(err, repo.ErrApiNotRunning)
}

Try / catch

apiAddr, err := fsrepo.APIAddr(cfgRoot)
switch {
case err == nil:
	// use apiAddr
case errors.Is(err, repo.ErrApiNotRunning):
	// daemon offline: start daemon or proceed offline
default:
	return err
}

Prevention

When it happens

Trigger: Calling fsrepo.APIAddr(configRoot) when $IPFS_PATH/api is absent (daemon never started or already stopped), or makeExecutor / RPC clients resolving the API address before `ipfs daemon` is running.

Common situations: Running CLI commands expecting a daemon with only an initialized repo, daemon crashed or killed leaving stale repo state, wrong IPFS_PATH pointing at a repo with no api file, or scripts racing daemon startup.

Related errors


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