ipfs/kubo · error
invalid key
Error message
invalid key
What it means
normalizeKey validates an IPNS/pk routing key path, which must have the form /ipns/<peerid> or /pk/<peerid> (three slash-separated parts, empty first). Anything else — wrong prefix, missing parts, extra slashes — returns "invalid key" before the peer ID is even decoded. It is a strict path-format validation.
Source
Thrown at core/coreapi/routing.go:65
err = api.checkOnline(options.AllowOffline)
if err != nil {
return err
}
dhtKey, err := normalizeKey(key)
if err != nil {
return err
}
return api.routing.PutValue(ctx, dhtKey, value)
}
func normalizeKey(s string) (string, error) {
parts := strings.Split(s, "/")
if len(parts) != 3 ||
parts[0] != "" ||
!(parts[1] == "ipns" || parts[1] == "pk") {
return "", errors.New("invalid key")
}
k, err := peer.Decode(parts[2])
if err != nil {
return "", err
}
return strings.Join(append(parts[:2], string(k)), "/"), nil
}
func (api *RoutingAPI) FindPeer(ctx context.Context, p peer.ID) (peer.AddrInfo, error) {
ctx, span := tracing.Span(ctx, "CoreAPI.DhtAPI", "FindPeer", trace.WithAttributes(attribute.String("peer", p.String())))
defer span.End()
err := api.checkOnline(false)
if err != nil {
return peer.AddrInfo{}, err
}
pi, err := api.routing.FindPeer(ctx, peer.ID(p))View on GitHub (pinned to 329838acdf)
Solutions
- Format the key as /ipns/<peerID> or /pk/<peerID>, with leading slash and exactly three segments.
- Ensure the third segment decodes as a valid libp2p peer ID (use peer.Decode-compatible formats).
- Build the path with fmt.Sprintf("/ipns/%s", id) from a peer.ID rather than concatenating strings.
- If the value is a DNSLink name, resolve it to a peer ID first — DNS names are not valid here.
Example fix
// before val, err := api.Routing().Get(ctx, "ipns/12D3KooW...") // after val, err := api.Routing().Get(ctx, "/ipns/12D3KooW...")
Defensive patterns
Strategy: validation
Validate before calling
func validRoutingKey(s string) bool {
parts := strings.Split(s, "/")
if len(parts) != 3 || parts[0] != "" || (parts[1] != "ipns" && parts[1] != "pk") {
return false
}
_, err := peer.Decode(parts[2])
return err == nil
} Type guard
func toRoutingKey(id peer.ID) (string, bool) {
if id == "" {
return "", false
}
return "/ipns/" + id.String(), true
} Try / catch
val, err := api.Routing().Get(ctx, key)
if err != nil && strings.Contains(err.Error(), "invalid key") {
return fmt.Errorf("key %q must be /ipns/<peerid> or /pk/<peerid>: %w", key, err)
} Prevention
- Build keys with fmt.Sprintf("/ipns/%s", peerID) instead of manual concatenation
- Decode the peer ID with peer.Decode before forming the path
- Never pass DNS names or CIDs where a peer ID is required
When it happens
Trigger: Calling Routing().Get or Routing().Put with keys like "ipns/foo", "/ipns", "/ipfs/foo", "/pk/<id>/extra", or a raw peer id without the leading slash and namespace.
Common situations: Scripts that build the key path by hand and forget the leading slash, using the wrong namespace prefix (ipfs instead of ipns/pk), and passing CIDs or DNSNames where a peer ID is required.
Related errors
- number of providers must be greater than 0
- supernode routing was never fully implemented and has been r
- Routing.AcceleratedDHTClient option is set even tho Routing.
- unrecognized routing option: %s
- block %s not found locally, cannot provide
AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03).
Data as JSON: /api/errors/fa853b252eb41ef1.
Report an issue: GitHub.