hashicorp/nomad · error

invalid key type: %T

Error message

invalid key type: %T

What it means

keyID was given a public key whose concrete Go type is neither *ecdsa.PublicKey nor *rsa.PublicKey, so the switch falls through to the default and refuses to compute an RFC 5280 Subject Key Identifier. This is a programming error in the caller, not a data-corruption issue.

Source

Thrown at helper/tlsutil/generate.go:267

		return "", "", err
	}

	var buf bytes.Buffer
	err = pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: bs})
	if err != nil {
		return "", "", fmt.Errorf("error encoding private key: %s", err)
	}

	return buf.String(), pk, nil
}

// KeyId returns a x509 KeyId from the given signing key.
func keyID(raw interface{}) ([]byte, error) {
	switch raw.(type) {
	case *ecdsa.PublicKey:
	case *rsa.PublicKey:
	default:
		return nil, fmt.Errorf("invalid key type: %T", raw)
	}

	// This is not standard; RFC allows any unique identifier as long as they
	// match in subject/authority chains but suggests specific hashing of DER
	// bytes of public key including DER tags.
	bs, err := x509.MarshalPKIXPublicKey(raw)
	if err != nil {
		return nil, err
	}

	// String formatted
	kID := sha256.Sum256(bs)
	return kID[:], nil
}

// ParseCert parses the x509 certificate from a PEM-encoded value.
func ParseCert(pemValue string) (*x509.Certificate, error) {
	// The _ result below is not an error but the remaining PEM bytes.

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Pass the public key (e.g. signer.Public()) rather than the private key to keyID.
  2. Use an ECDSA (P-256) or RSA private key when generating CAs/certs with this helper.
  3. If you need Ed25519, extend keyID's switch to handle *ed25519.PublicKey.
  4. Verify any custom crypto.Signer implementation's Public() returns *ecdsa.PublicKey or *rsa.PublicKey.

Example fix

// before
signer := ed25519.GenerateKey(rand.Reader)
kid, err := keyID(signer)
// after
ecdsaKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
kid, err := keyID(&ecdsaKey.PublicKey)
Defensive patterns

Strategy: type-guard

Validate before calling

func isSupportedSigner(s crypto.Signer) error {
	switch s.Public().(type) {
	case *ecdsa.PublicKey, *rsa.PublicKey:
		return nil
	default:
		return fmt.Errorf("unsupported key type %T; use ECDSA or RSA", s.Public())
	}
}

Type guard

func isSupportedPublicKey(pub interface{}) bool {
	switch pub.(type) {
	case *ecdsa.PublicKey, *rsa.PublicKey:
		return true
	}
	return false
}

Try / catch

if !isSupportedPublicKey(signer.Public()) {
	return fmt.Errorf("cannot compute key ID for %T", signer.Public())
}
kid, err := keyID(signer.Public())
if err != nil { return err }

Prevention

When it happens

Trigger: Calling keyID (directly, or indirectly via GenerateCA/GenerateCert with a custom signer) with an Ed25519 public key, ed25519.PrivateKey passed instead of its Public(), or any other crypto.Signer implementation.

Common situations: Forking or extending the CA code to use Ed25519 or a PKCS#11/HSM-backed signer; accidentally passing a private key rather than signer.Public(); refactoring so the wrong variable is handed to keyID.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/413b905a6046c3f9. Report an issue: GitHub.