ory/hydra · error
square/go-jose: parse error, got '%s', '%s', '%s' and '%s'
Error message
square/go-jose: parse error, got '%s', '%s', '%s' and '%s'
What it means
Aggregated parse error from LoadPrivateKey: none of the four attempted formats (PKCS1, PKCS8, EC PEM, JWK) succeeded, and the message embeds each attempt's underlying error so the real cause of the malformed private key can be diagnosed.
Source
Thrown at oryx/josex/utils.go:102
return priv, nil
}
priv, err1 := x509.ParsePKCS8PrivateKey(input)
if err1 == nil {
return priv, nil
}
priv, err2 := x509.ParseECPrivateKey(input)
if err2 == nil {
return priv, nil
}
jwk, err3 := LoadJSONWebKey(input, false)
if err3 == nil {
return jwk, nil
}
return nil, fmt.Errorf("square/go-jose: parse error, got '%s', '%s', '%s' and '%s'", err0, err1, err2, err3)
}
View on GitHub (pinned to 4174065ffb)
Solutions
- Read err0..err3 in the message to see each parse failure reason
- Confirm the input is an unencrypted PEM PRIVATE KEY (PKCS1 or PKCS8), DER private key, or JWK with a private 'd' component
- Decrypt password-protected keys before passing them in (openssl pkey -in key.pem)
- If you passed a public key or certificate, load the actual private key file
- Check for whitespace/newline mangling when keys come from env vars
Example fix
// before key, err := josex.LoadPrivateKey(certPEM) // 'BEGIN CERTIFICATE' // after key, err := josex.LoadPrivateKey(privPEM) // 'BEGIN PRIVATE KEY'
Defensive patterns
Strategy: validation
Validate before calling
func looksLikePrivateKey(data []byte) error {
s := strings.TrimSpace(string(data))
switch {
case strings.Contains(s, "BEGIN ENCRYPTED PRIVATE KEY") || strings.Contains(s, "ENCRYPTED PRIVATE KEY"):
return errors.New("key is passphrase-protected; decrypt before loading")
case strings.Contains(s, "BEGIN CERTIFICATE") || strings.Contains(s, "BEGIN PUBLIC KEY"):
return errors.New("got a public key/certificate; LoadPrivateKey needs a private key")
case strings.Contains(s, "BEGIN PRIVATE KEY"), strings.Contains(s, "BEGIN RSA PRIVATE KEY"), strings.HasPrefix(s, "{\"kty\""):
return nil
default:
return errors.New("input is not a PEM private key, DER private key, or JWK")
}
} Type guard
func isPEMPrivateKey(data []byte) bool {
s := string(data)
return strings.Contains(s, "BEGIN PRIVATE KEY") || strings.Contains(s, "BEGIN RSA PRIVATE KEY")
} Try / catch
key, err := josex.LoadPrivateKey(data)
if err != nil {
return fmt.Errorf("invalid private key material: %w", err)
} Prevention
- Keep public and private keys in separate, clearly named files and double-check paths in config
- Decrypt passphrase-protected PEMs at provisioning time (openssl pkey)
- Watch for newline mangling when keys pass through env vars or secrets templates
- Load all crypto material at startup so bad keys fail fast, not on first request
When it happens
Trigger: Calling josex.LoadPrivateKey with a public key instead of a private key, a certificate PEM, encrypted (password-protected) private key PEM, raw base64 of key material, or corrupt/empty data.
Common situations: Swapped pub/priv file paths in config; passphrase-protected 'ENCRYPTED PRIVATE KEY' blocks the parser cannot read; Kubernetes secrets mounted truncated; copied keys with HTML entities or escaped newlines.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- square/go-jose: parse error, got '%s', '%s' and '%s'
- invalid JWK key
- unknown algorithm %s for signing key
- unknown algorithm %s for encryption key
- invalid elliptic curve key size, this algorithm does not sup
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/3d845e504ed3fc84.
Report an issue: GitHub.