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
- Ensure kty is 'RSA' and both n and e are present non-empty strings
- Read the wrapped message to identify the missing field
- Re-export the full JWK from the source key
- 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
- Require kty, n, e in fixture linting before test runs
- If d is present, require the full private field set to avoid later failures
- Do not feed JWT headers or partial keys to importKey
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
- invalid EC JWK key: %w
- failed to parse input as RSA JWK key: %w
- failed to decode modulus: %w
- failed to decode exponent: %w
- failed to decode private exponent: %w
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/579b58cef2171091.
Report an issue: GitHub.