ipfs/kubo · error

building fx opts: %w

Error message

building fx opts: %w

What it means

NewNode in core/builder.go builds the fx dependency-injection options by running each user-supplied fxOptionFunc; if any of these callback functions returns an error, node construction aborts and the error is wrapped with 'building fx opts'. The wrapped error comes from the specific option func (e.g. plugins, repo inspection, host setup), so inspect the %w chain for the root cause.

Source

Thrown at core/builder.go:84

	ctx, cancel := context.WithCancel(valueContext{ctx})

	// add a metrics scope.
	ctx = metrics.CtxScope(ctx, "ipfs")

	n := &IpfsNode{
		ctx: ctx,
	}

	opts := []fx.Option{
		node.IPFS(ctx, cfg),
		fx.NopLogger,
	}
	for _, optFunc := range fxOptionFuncs {
		var err error
		opts, err = optFunc(FXNodeInfo{FXOptions: opts})
		if err != nil {
			cancel()
			return nil, fmt.Errorf("building fx opts: %w", err)
		}
	}
	//nolint:staticcheck // https://github.com/ipfs/kubo/pull/9423#issuecomment-1341038770
	opts = append(opts, fx.Extract(n))

	app := fx.New(opts...)

	var once sync.Once
	var stopErr error
	n.stop = func() error {
		once.Do(func() {
			// Bound app.Stop with a deadline so an FX OnStop hook that
			// never returns cannot hang the daemon. ShutdownTimeout==0
			// opts out of the cap entirely and restores the legacy
			// behavior of waiting forever for hooks to complete. The
			// daemon's watchdog in cmd/ipfs/kubo/daemon.go fires at the
			// same deadline and is the unconditional os.Exit fallback.
			stopCtx := context.Background()

View on GitHub (pinned to 329838acdf)

Solutions

  1. Read the wrapped (%w) cause with errors.Unwrap/errors.Is to find the failing option func.
  2. Check repo integrity and datastore availability (ipfs repo fsck, disk space, permissions).
  3. Fix or remove the failing fx option func in the node construction call.

Example fix

// before
node, err := core.NewNode(ctx, &core.BuildCfg{}, opts...) // opaque error
// after
if err != nil {
    log.Errorf("node build failed: %+v", err) // print full unwrap chain
    if errors.Is(err, repo.ErrNoRepo) { /* init repo first */ }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight: ensure repo exists and is accessible before NewNode
if err := repoApi.Err(); err != nil { /* init repo */ }
if _, err := os.Stat(ipfsPath); err != nil {
    return fmt.Errorf("repo missing, run ipfs init: %w", err)
}

Type guard

func isFxOptBuildError(err error) bool {
    return err != nil && strings.Contains(err.Error(), "building fx opts")
}

Try / catch

n, err := core.NewNode(ctx, &core.BuildCfg{}, opts...)
if err != nil {
    if isFxOptBuildError(err) {
        cause := errors.Unwrap(err) // inspect failing option func
        log.Errorf("fx option failed: %v", cause)
    }
    cancel()
    return err
}

Prevention

When it happens

Trigger: Calling core.NewNode with FXOption funcs that fail — e.g. an fx option that opens the repo/blockstore and hits a corrupted datastore, or a plugin-loading option that errors.

Common situations: Embedding kubo as a library (kubo-as-a-library examples); daemon startup failing on repo/datastore issues surfaced by an option func; custom integrations passing faulty options.

Related errors


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