ory/hydra · error

square/go-jose: parse error, got '%s', '%s' and '%s'

Error message

square/go-jose: parse error, got '%s', '%s' and '%s'

What it means

LoadPublicKey tries to parse the input bytes three ways: as PEM (ParsePKIXPublicKey), as DER, and as a JWK (LoadJSONWebKey). If all three fail, it aggregates the three errors into this single parse-error message.

Source

Thrown at oryx/josex/utils.go:69

	}

	// Try to load SubjectPublicKeyInfo
	pub, err0 := x509.ParsePKIXPublicKey(input)
	if err0 == nil {
		return pub, nil
	}

	cert, err1 := x509.ParseCertificate(input)
	if err1 == nil {
		return cert.PublicKey, nil
	}

	jwk, err2 := LoadJSONWebKey(data, true)
	if err2 == nil {
		return jwk, nil
	}

	return nil, fmt.Errorf("square/go-jose: parse error, got '%s', '%s' and '%s'", err0, err1, err2)
}

// LoadPrivateKey loads a private key from PEM/DER/JWK-encoded data.
func LoadPrivateKey(data []byte) (interface{}, error) {
	input := data

	block, _ := pem.Decode(data)
	if block != nil {
		input = block.Bytes
	}

	var priv interface{}
	priv, err0 := x509.ParsePKCS1PrivateKey(input)
	if err0 == nil {
		return priv, nil
	}

	priv, err1 := x509.ParsePKCS8PrivateKey(input)

View on GitHub (pinned to 4174065ffb)

Solutions

  1. Inspect err0/err1/err2 in the message — they show exactly why PEM, DER, and JWK parsing each failed
  2. Ensure the input is a PEM 'BEGIN PUBLIC KEY' block, raw DER SPKI bytes, or a JWK JSON object
  3. If you have a certificate, extract its public key first (x509 cert .PublicKey) or use a loader that accepts certificates
  4. If you only have a private key, derive the public key from it and pass that
  5. Verify the file/env value is non-empty and not truncated

Example fix

// before
data, _ := os.ReadFile("server.key") // private key PEM
jwk, err := josex.LoadPublicKey(data)
// after
data, _ := os.ReadFile("server.pub") // PEM PUBLIC KEY
jwk, err := josex.LoadPublicKey(data)
Defensive patterns

Strategy: validation

Validate before calling

func looksLikePublicKey(data []byte) error {
    s := strings.TrimSpace(string(data))
    switch {
    case strings.HasPrefix(s, "-----BEGIN PUBLIC KEY-----"),
        strings.HasPrefix(s, "{\"kty\""):
        return nil
    case strings.HasPrefix(s, "-----BEGIN CERTIFICATE-----"):
        return errors.New("got a certificate; extract the public key first")
    case strings.Contains(s, "PRIVATE KEY"):
        return errors.New("got a private key; LoadPublicKey needs the public key")
    default:
        return errors.New("input is neither PEM PUBLIC KEY nor JWK JSON")
    }
}

Type guard

func isPEMPublicKey(data []byte) bool {
    return strings.HasPrefix(strings.TrimSpace(string(data)), "-----BEGIN PUBLIC KEY-----")
}
func isJWK(data []byte) bool {
    return json.Valid(data) && strings.Contains(string(data), "\"kty\"")
}

Try / catch

jwk, err := josex.LoadPublicKey(data)
if err != nil {
    return fmt.Errorf("invalid public key material: %w", err)
}

Prevention

When it happens

Trigger: Calling josex.LoadPublicKey with data that is none of PEM PKIX public key, DER public key, or JWK JSON — e.g. a private-key PEM, a raw base64 key, an x509 certificate instead of a public key, or truncated/garbled bytes.

Common situations: Pointing config at a private key file when a public key is required; pasting a certificate (-----BEGIN CERTIFICATE-----) instead of -----BEGIN PUBLIC KEY-----; wrong env var or file mounted empty; whitespace/BOM corruption.

Understand the failure class

Related errors


AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03). Data as JSON: /api/errors/f1bb6f27e3641cf3. Report an issue: GitHub.