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
- 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"'`).
- 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.
- If the config is generated programmatically, compare against the exported constants config.DHTModeClient/DHTModeServer/DHTModeAuto rather than hand-written strings.
- 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
- Always assign DHT.Mode from the config.DHTMode* constants, never raw strings.
- Run `ipfs config --json Routing.DHT` to inspect the value before starting the daemon.
- Normalize user input (trim/lowercase) before writing it into the config.
- Pin config schema validation in tests that reject unknown DHT.Mode values.
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
- Routing.AcceleratedDHTClient option is set even tho Routing.
- GetClosestPeers not supported: WAN DHT is not available
- private networking (swarm.key / LIBP2P_FORCE_PNET) does not
- supernode routing was never fully implemented and has been r
- unrecognized routing option: %s
AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03).
Data as JSON: /api/errors/0c14cadd722341d1.
Report an issue: GitHub.