ipfs/kubo · error

failed to derive PeerID from PrivKey: %w

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.

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)

Solutions

  1. Replace the key with a known-good one: re-copy Identity.PrivKey from a backup of the original config
  2. Regenerate the identity: `ipfs init` in a fresh directory and migrate pins/data, accepting the PeerID change
  3. 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
  4. 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

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


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