golang/go · error

private key seed not available

Error message

private key seed not available

What it means

Raised by hybridPrivateKey.Bytes() when k.seed is nil. The seed is only retained when the key was constructed through the generate/derive path that captures it; a key assembled from externally supplied parts has no storable seed, so returning the raw private bytes is impossible.

Source

Thrown at src/crypto/hpke/pq.go:320

	}
}

func (kem *hybridKEM) DeriveKeyPair(ikm []byte) (PrivateKey, error) {
	suiteID := byteorder.BEAppendUint16([]byte("KEM"), kem.id)
	dk, err := SHAKE256().labeledDerive(suiteID, ikm, "DeriveKeyPair", nil, 32)
	if err != nil {
		return nil, err
	}
	return kem.NewPrivateKey(dk)
}

func (k *hybridPrivateKey) KEM() KEM {
	return k.kem
}

func (k *hybridPrivateKey) Bytes() ([]byte, error) {
	if k.seed == nil {
		return nil, errors.New("private key seed not available")
	}
	return k.seed, nil
}

func (k *hybridPrivateKey) PublicKey() PublicKey {
	return &hybridPublicKey{
		kem: k.kem,
		t:   k.t.PublicKey(),
		pq:  k.pq.Encapsulator(),
	}
}

func (k *hybridPrivateKey) decap(enc []byte) ([]byte, error) {
	if len(enc) != k.kem.pqCiphertextSize+k.kem.curvePointSize {
		return nil, errors.New("invalid encapsulated key size")
	}
	ctPQ, ctT := enc[:k.kem.pqCiphertextSize], enc[k.kem.pqCiphertextSize:]
	ssPQ, err := k.pq.Decapsulate(ctPQ)

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Generate the key via the suite's KEM.GenerateKey() or DeriveKeyPair() so the seed is retained and Bytes() succeeds.
  2. If you must assemble from parts, store the seed yourself at construction time instead of relying on Bytes().
  3. Check for the error (or pre-check whether the key came from the generate path) before attempting serialization.

Example fix

// before
priv, _ := MLKEM768P256().NewPrivateKey(externalParts) // seed == nil
seed, err := priv.Bytes() // errors

// after
priv, _ := MLKEM768P256().GenerateKey(rand.Reader) // seed retained
seed, err := priv.Bytes() // ok
Defensive patterns

Strategy: try-catch

Validate before calling

// Before serializing, confirm the key came from a seed-retaining path.
func canSerialize(p hpke.PrivateKey) bool {
    _, err := p.Bytes()
    return err == nil
}

Try / catch

if b, err := priv.Bytes(); err != nil {
    if err.Error() == "private key seed not available" {
        // regenerate from seed or refuse to persist
    }
    return err
} else {
    _ = b
}

Prevention

When it happens

Trigger: Calling PrivateKey.Bytes() on a hybridPrivateKey whose seed field is nil — typically a key built via NewHybridPrivateKey from pre-existing ML-KEM and ECDH key material rather than generated/derived in-package.

Common situations: Serializing a hybrid private key for storage/transport after constructing it from independently generated parts; calling Bytes() on a key obtained via NewHybridPrivateKey rather than GenerateKey/DeriveKeyPair; persistence code that assumes every private key is serializable.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/6fe7a803c69864e6. Report an issue: GitHub.