ipfs/kubo · error
failed to derive PeerID from PrivKey
Error message
failed to derive PeerID from PrivKey: %w
What it means
After decoding PrivKey into a crypto private key, nodePeerID derives the libp2p PeerID with peer.IDFromPrivateKey. This wraps a failure of that derivation — the decoded key bytes are not usable to compute the corresponding PeerID (malformed key structure despite passing base64 decode). Rare, since decode and derivation usually fail together.
Solutions
- Replace the key with a known-good one: re-copy Identity.PrivKey from a backup of the original config
- Regenerate the identity: `ipfs init` in a fresh directory and migrate pins/data, accepting the PeerID change
- Verify the key round-trips in a scratch repo: set it there and run `ipfs id`; if that fails, the key material itself is corrupt
- Check the underlying wrapped error (%w) for the specific crypto failure to confirm it's the key, not the repo
Example fix
// before: corrupted key from a lossy transfer "PrivKey": "CAESqA…(truncated)…" // after: exact base64 string from backup "PrivKey": "CAESqA...==" # copied byte-for-byte
Defensive patterns
Strategy: retry
Validate before calling
# verify the key works in a scratch repo before trusting it ipfs init /tmp/scratch-repo && IPFS_PATH=/tmp/scratch-repo ipfs config --json Identity.PrivKey "$(jq -r .Identity.PrivKey config.json)"
Try / catch
id, err := peer.IDFromPrivateKey(pk)
if err != nil {
return fmt.Errorf("decoded PrivKey cannot yield a PeerID (restore key from backup): %w", err)
} Prevention
- Restore Identity.PrivKey from a known-good backup rather than repairing corrupted material
- Round-trip test the key in a scratch repo (`ipfs id`) before deploying it to production configs
- Avoid merging config fragments from different repos — take Identity wholesale from one source
- Note PeerID changes if you regenerate; plan pin/data migration accordingly
When it happens
Trigger: A PrivKey string that base64-decodes and unmarshals but yields a key with invalid/missing public component; corrupted key material; keys of types whose PeerID derivation fails in the linked libp2p version.
Common situations: Configs assembled by merging fragments from different repos; keys altered by lossy text processing (charset conversion, line-wrapping corruption) that base64 still happens to accept.
Related errors
- cannot set Identity.PeerID to a value that does not match…
- decoding old private key
- failed to decode PrivKey
- failed to get PrivKey
- private key in config does not match id
AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03).
Data as JSON: /api/errors/81808802bdc55928.
Report an issue: GitHub.
Appendix: source
Thrown at core/commands/config.go:643
// config. Identity.PeerID must equal this value; the node refuses to start
// when the two disagree.
func nodePeerID(r repo.Repo) (peer.ID, error) {
keyF, err := getConfig(r, config.PrivKeySelector)
if err != nil {
return "", errors.New("failed to get PrivKey")
}
pkstr, ok := keyF.Value.(string)
if !ok {
return "", errors.New("private key in config was not a string")
}
ident := config.Identity{PrivKey: pkstr}
pk, err := ident.DecodePrivateKey("")
if err != nil {
return "", fmt.Errorf("failed to decode PrivKey: %w", err)
}
id, err := peer.IDFromPrivateKey(pk)
if err != nil {
return "", fmt.Errorf("failed to derive PeerID from PrivKey: %w", err)
}
return id, nil
}
func replaceConfig(r repo.Repo, file io.Reader) error {
var newCfg config.Config
if err := json.NewDecoder(file).Decode(&newCfg); err != nil {
return errors.New("failed to decode file as config")
}
// Handle Identity.PrivKey (secret)
if len(newCfg.Identity.PrivKey) != 0 {
return errors.New("setting private key with API is not supported")
}
keyF, err := getConfig(r, config.PrivKeySelector)
if err != nil {View on GitHub (pinned to 329838acdf)