grafana/k6 · error

invalid RSA JWK key: %w

Error message

invalid RSA JWK key: %w

What it means

After parsing, importRSAJWK runs rsaJWK.validate(), which requires kty == 'RSA' plus non-empty n (modulus) and e (exponent); other private fields are deliberately not validated yet (see the TODO in the source). This error wraps any of those failures and is returned from crypto.subtle.importKey('jwk', ...) for RSA algorithms. The wrapped text identifies the failing field ('invalid key type: ...', 'modulus (n) is required', 'exponent (e) is required').

Source

Thrown at internal/js/modules/k6/webcrypto/jwk.go:331

		return errors.New("modulus (n) is required")
	}

	if jwk.E == "" {
		return errors.New("exponent (e) is required")
	}

	// TODO: consider validating the other fields in future
	return nil
}

func importRSAJWK(jsonKeyData []byte) (any, CryptoKeyType, int, error) {
	var jwk rsaJWK
	if err := json.Unmarshal(jsonKeyData, &jwk); err != nil {
		return nil, UnknownCryptoKeyType, 0, fmt.Errorf("failed to parse input as RSA JWK key: %w", err)
	}

	if err := jwk.validate(); err != nil {
		return nil, UnknownCryptoKeyType, 0, fmt.Errorf("invalid RSA JWK key: %w", err)
	}

	// decode the various key components
	nBytes, err := base64URLDecode(jwk.N)
	if err != nil {
		return nil, UnknownCryptoKeyType, 0, fmt.Errorf("failed to decode modulus: %w", err)
	}
	eBytes, err := base64URLDecode(jwk.E)
	if err != nil {
		return nil, UnknownCryptoKeyType, 0, fmt.Errorf("failed to decode exponent: %w", err)
	}

	// convert exponent to an integer
	eInt := new(big.Int).SetBytes(eBytes).Int64()
	pubKey := rsa.PublicKey{
		N: new(big.Int).SetBytes(nBytes),
		E: int(eInt),
	}

View on GitHub (pinned to 93accf6570)

Solutions

  1. Ensure kty is 'RSA' and both n and e are present non-empty strings
  2. Read the wrapped message to identify the missing field
  3. Re-export the full JWK from the source key
  4. Verify the JWK was not truncated by config templating or environment variables

Example fix

// before
const jwk = { kty: 'RSA', n: '...' }; // exponent missing
// after
const jwk = { kty: 'RSA', n: '...', e: 'AQAB' };
Defensive patterns

Strategy: validation

Validate before calling

function isValidRsaPublicJwk(jwk) {
  return jwk && typeof jwk === 'object' &&
    jwk.kty === 'RSA' &&
    typeof jwk.n === 'string' && jwk.n !== '' &&
    typeof jwk.e === 'string' && jwk.e !== '';
}
if (!isValidRsaPublicJwk(jwk)) throw new Error('RSA JWK needs kty="RSA" plus non-empty n and e');

Type guard

function isCompleteRsaJwk(jwk) {
  return !!jwk && typeof jwk === 'object' && jwk.kty === 'RSA' &&
    jwk.n && jwk.e && (jwk.d === undefined || (jwk.p && jwk.q && jwk.dp && jwk.dq && jwk.qi));
}

Try / catch

try {
  key = await crypto.subtle.importKey('jwk', jwk, rsaAlg, true, usages);
} catch (e) {
  if (e.message.includes('invalid RSA JWK key')) {
    throw new Error(`RSA JWK invalid: kty=${jwk.kty} n=${!!jwk.n} e=${!!jwk.e}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: RSA JWK import with kty not exactly 'RSA'; missing or empty n; missing or empty e. Present but malformed d/p/q/dp/dq/qi do not trigger this error (they fail later during decode or key validation).

Common situations: Public JWKs truncated during copying (missing e); JWKs exported with only kty and n; feeding JWT header fragments (no key material) to importKey.

Related errors


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/579b58cef2171091. Report an issue: GitHub.