ipfs/kubo · error

invalid DHT mode: %q

Error message

invalid DHT mode: %q

What it means

This error comes from the delegated routing V2 router construction in kubo (routing/delegated.go). When building a DHT router from Routing.Type="dht" configuration, dhtRoutingFromConfig maps the configured DHT.Mode string onto a go-libp2p-kad-dht mode option, accepting only "auto", "client", or "server". If params.Mode holds any other value, the switch falls through to the default branch and the router cannot be created, so it returns this error instead of a routing.Routing.

Source

Thrown at routing/delegated.go:331

	params, ok := conf.Parameters.(*config.DHTRouterParams)
	if !ok {
		return nil, errors.New("incorrect params for DHT router")
	}

	if params.AcceleratedDHTClient {
		return createFullRT(extra)
	}

	var mode dht.ModeOpt
	switch params.Mode {
	case config.DHTModeAuto:
		mode = dht.ModeAuto
	case config.DHTModeClient:
		mode = dht.ModeClient
	case config.DHTModeServer:
		mode = dht.ModeServer
	default:
		return nil, fmt.Errorf("invalid DHT mode: %q", params.Mode)
	}

	return createDHT(extra, params.PublicIPNetwork, mode)
}

func createDHT(params *ExtraDHTParams, public bool, mode dht.ModeOpt) (routing.Routing, error) {
	var opts []dht.Option

	if public {
		opts = append(opts, dht.QueryFilter(dht.PublicQueryFilter),
			dht.RoutingTableFilter(dht.PublicRoutingTableFilter),
			dht.RoutingTablePeerDiversityFilter(dht.NewRTPeerDiversityFilter(params.Host, 2, 3)))
	} else {
		opts = append(opts, dht.ProtocolExtension(dual.LanExtension),
			dht.QueryFilter(dht.PrivateQueryFilter),
			dht.RoutingTableFilter(dht.PrivateRoutingTableFilter))
	}

View on GitHub (pinned to 329838acdf)

Solutions

  1. Open the kubo config (config file or --json flag) and set Routing.DHT.Mode to exactly "client", "server", or "auto" (lowercase, e.g. `ipfs config --json Routing.DHT.Mode '"client"'`).
  2. If you do not need a specific DHT role, remove the Mode key or set it to "auto" so kubo picks server/client based on reachability.
  3. If the config is generated programmatically, compare against the exported constants config.DHTModeClient/DHTModeServer/DHTModeAuto rather than hand-written strings.
  4. Check the daemon log/startup error for the %q value printed; fix that exact string in the configuration and restart.

Example fix

// before (config JSON)
"Routing": { "Type": "dht", "DHT": { "Mode": "Client" } }
// after
"Routing": { "Type": "dht", "DHT": { "Mode": "client" } }
Defensive patterns

Strategy: validation

Validate before calling

mode := strings.ToLower(strings.TrimSpace(cfg.Routing.DHT.Mode))
switch config.DHTMode(mode) {
case "", config.DHTModeAuto, config.DHTModeClient, config.DHTModeServer:
	// valid
default:
	return fmt.Errorf("Routing.DHT.Mode %q invalid: must be auto, client, or server", mode)
}

Type guard

func validDHTMode(m config.DHTMode) bool {
	switch m {
	case "", config.DHTModeAuto, config.DHTModeClient, config.DHTModeServer:
		return true
	}
	return false
}

Try / catch

r, err := parse(ctx, cfg)
if err != nil {
	var mode config.DHTMode
	if strings.Contains(err.Error(), "invalid DHT mode") {
		// log the offending value and fall back to auto
		r, err = parseWithMode(ctx, cfg, config.DHTModeAuto)
	}
	if err != nil {
		return nil, err
	}
	_ = mode
}

Prevention

When it happens

Trigger: Calling parse -> dhtRoutingFromConfig with a DHTRouterParams whose Mode field is set to something other than config.DHTModeAuto ("auto"), config.DHTModeClient ("client"), or config.DHTModeServer ("server") — e.g. Routing.Type is "dht" and Routing.DHT.Mode is a typo or an unsupported string.

Common situations: Typing the mode in the kubo config JSON (e.g. "Mode": "dht", "Mode": "Server", "Mode": "client-mode") instead of the exact lowercase "client", "server", or "auto"; generating the config from a script that writes an empty-but-present Mode value not matched by the case (empty string only passes if the code treats it as auto — any non-empty invalid string fails); migrating configs between versions where an old mode name is no longer recognized.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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