ory/hydra · error

jwksx: "%s" does not support arbitrary key length

Error message

jwksx: "%s" does not support arbitrary key length

What it means

generate() validates the requested bit size for elliptic-curve and EdDSA algorithms (ES256/ES384/ES512/EdDSA). These algorithms have fixed key sizes (256, 384, 521, 256 bits respectively), so any non-zero bits value that differs from the fixed size is rejected with this error. Passing bits=0 uses the algorithm's default size and is allowed.

Source

Thrown at oryx/jwksx/generator.go:65

	return []string{
		string(jose.HS256), string(jose.HS384), string(jose.HS512),
		string(jose.ES256), string(jose.ES384), string(jose.ES512), string(jose.EdDSA),
		string(jose.RS256), string(jose.RS384), string(jose.RS512), string(jose.PS256), string(jose.PS384), string(jose.PS512),
	}
}

// generate generates keypair for corresponding SignatureAlgorithm.
func generate(alg jose.SignatureAlgorithm, bits int) (crypto.PrivateKey, error) {
	switch alg {
	case jose.ES256, jose.ES384, jose.ES512, jose.EdDSA:
		keylen := map[jose.SignatureAlgorithm]int{
			jose.ES256: 256,
			jose.ES384: 384,
			jose.ES512: 521, // sic!
			jose.EdDSA: 256,
		}
		if bits != 0 && bits != keylen[alg] {
			return nil, errors.Errorf(`jwksx: "%s" does not support arbitrary key length`, alg)
		}
	case jose.RS256, jose.RS384, jose.RS512, jose.PS256, jose.PS384, jose.PS512:
		if bits == 0 {
			bits = 2048
		}
		if bits < 2048 {
			return nil, errors.Errorf(`jwksx: key size must be at least 2048 bit for algorithm "%s"`, alg)
		}
	case jose.HS256:
		if bits == 0 {
			bits = 256
		}
		if bits < 256 {
			return nil, errors.Errorf(`jwksx: key size must be at least 256 bit for algorithm "%s"`, alg)
		}
	case jose.HS384:
		if bits == 0 {
			bits = 384

View on GitHub (pinned to 4174065ffb)

Solutions

  1. Pass bits=0 to use the algorithm's default key size
  2. Pass the exact fixed size: 256 for ES256/EdDSA, 384 for ES384, 521 (not 512) for ES512
  3. Switch to an RSA (RS*/PS*) or HMAC (HS*) algorithm if an arbitrary key length is genuinely required

Example fix

// before
jwks, err := jwksx.GenerateSigningKeys("kid", "ES256", 2048)
// after
jwks, err := jwksx.GenerateSigningKeys("kid", "ES256", 0) // or 256
Defensive patterns

Strategy: validation

Validate before calling

func validBitsForAlg(alg string, bits int) error {
	fixed := map[string]int{"ES256": 256, "ES384": 384, "ES512": 521, "EdDSA": 256}
	if want, ok := fixed[alg]; ok && bits != 0 && bits != want {
		return fmt.Errorf("%s requires exactly %d bits (or 0 for default), got %d", alg, want, bits)
	}
	return nil
}

Try / catch

jwks, err := jwksx.GenerateSigningKeys(id, alg, bits)
if err != nil {
	if strings.Contains(err.Error(), "does not support arbitrary key length") {
		// retry with default size
		jwks, err = jwksx.GenerateSigningKeys(id, alg, 0)
	}
	return err
}

Prevention

When it happens

Trigger: Calling GenerateSigningKeys(id, alg, bits) with alg one of ES256, ES384, ES512, EdDSA and bits set to any value other than 0 or the algorithm's exact fixed size (256/384/521/256). E.g. GenerateSigningKeys(id, "ES256", 512).

Common situations: Reusing a generic key-generation helper that passes a user-supplied bits parameter (e.g. 2048 or 4096 from config) for all algorithms; assuming ES512 uses 512 bits when it actually uses 521 (P-521); copy-pasting RSA-style sizes into EC algorithm config.

Related errors


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