grafana/k6 · error
failed to validate private key: %w
Error message
failed to validate private key: %w
What it means
After decoding all members, k6 reconstructs a Go rsa.PrivateKey and calls Validate(), which verifies mathematical consistency: p*q == n, 0 < dp/dq/qi, d*e == 1 mod lambda(n), and CRT relations. This error means the fields decoded fine as base64url but do not form a valid RSA private key together.
Source
Thrown at internal/js/modules/k6/webcrypto/jwk.go:397
}
privKey := &rsa.PrivateKey{
PublicKey: pubKey,
D: new(big.Int).SetBytes(dBytes),
Primes: []*big.Int{
new(big.Int).SetBytes(pBytes),
new(big.Int).SetBytes(qBytes),
},
Precomputed: rsa.PrecomputedValues{
Dp: new(big.Int).SetBytes(dpBytes),
Dq: new(big.Int).SetBytes(dqBytes),
Qinv: new(big.Int).SetBytes(qiBytes),
},
}
err = privKey.Validate()
if err != nil {
return nil, UnknownCryptoKeyType, 0, fmt.Errorf("failed to validate private key: %w", err)
}
return privKey, PrivateCryptoKeyType, pubKey.N.BitLen(), nil
}
func exportRSAJWK(key *CryptoKey) (any, error) {
exported := &JsonWebKey{}
exported.Set("kty", "RSA")
switch rsaKey := key.handle.(type) {
case *rsa.PrivateKey:
exported.Set("n", base64URLEncode(rsaKey.N.Bytes()))
exported.Set("e", base64URLEncode(big.NewInt(int64(rsaKey.E)).Bytes()))
exported.Set("d", base64URLEncode(rsaKey.D.Bytes()))
exported.Set("p", base64URLEncode(rsaKey.Primes[0].Bytes()))
exported.Set("q", base64URLEncode(rsaKey.Primes[1].Bytes()))
exported.Set("dp", base64URLEncode(rsaKey.Precomputed.Dp.Bytes()))
exported.Set("dq", base64URLEncode(rsaKey.Precomputed.Dq.Bytes()))View on GitHub (pinned to 93accf6570)
Solutions
- Round-trip the key: import the original PEM/PKCS8 with importKey('pkcs8', ...), then exportKey('jwk') to get a guaranteed-consistent JWK
- Include ALL members kty, n, e, d, p, q, dp, dq, qi from the same key, byte-for-byte
- If CRT params are genuinely unavailable, import via PKCS8 PEM which lets Go recompute them, instead of a hand-built JWK
- Check that each member keeps its leading zero bytes exactly as exported (do not strip '0x00' prefixes yourself)
- Report/re-test after fixing: the error text after the colon names the exact failed relation (e.g. 'crypto/rsa: invalid prime' or consistency check)
Example fix
// before: hand-built JWK missing CRT params
const jwk = { kty: 'RSA', n, e, d, p, q }; // dp/dq/qi absent -> zero -> Validate fails
const key = await crypto.subtle.importKey('jwk', jwk, alg, true, ['decrypt']);
// after: import PKCS8 PEM and let k6 derive/reuse valid CRT values
const key = await crypto.subtle.importKey('pkcs8', pemBytes, alg, true, ['decrypt']);
const fullJwk = await crypto.subtle.exportKey('jwk', key); // now complete & consistent Defensive patterns
Strategy: try-catch
Validate before calling
function jwkLooksComplete(jwk) {
return ['kty','n','e','d','p','q','dp','dq','qi'].every(k => typeof jwk[k] === 'string' && jwk[k].length > 0);
}
if (!jwkLooksComplete(jwk)) throw new Error('JWK missing private/CRT members; use exportKey output'); Type guard
const isCompleteRsaPrivateJwk = j => j.kty === 'RSA' && ['n','e','d','p','q','dp','dq','qi'].every(k => typeof j[k] === 'string' && j[k].length > 0);
Try / catch
try { key = await crypto.subtle.importKey('jwk', jwk, alg, true, usages); }
catch (e) { console.error('RSA JWK inconsistent:', e.message, '- re-export from the source key'); throw e; } Prevention
- Never hand-edit or trim JWK members, including leading zero bytes
- Import via PKCS8/SPKI PEM when CRT params may be absent; Go recomputes them
- Round-trip once (import then export) to prove a key is usable before load tests depend on it
- Keep p, q, dp, dq, qi from the same keypair — mixing keys guarantees Validate failure
When it happens
Trigger: crypto.subtle.importKey('jwk', ...) where one of d, p, q, dp, dq, qi is empty or zero (missing members decode to the empty string, then to big.Int 0), or where the values belong to a different key / were reordered. Exporting a JWK and editing members by hand also lands here.
Common situations: Stripping CRT params (dp/dq/qi) from the JWK assuming they are optional; copying p and q from a different keypair than n; swapping dp and dq; trimming leading zero bytes inconsistently; a JWK pretty-printer mangling values; using a public JWK (no d/p/q) where earlier decode errors sometimes mask this one.
Related errors
- invalid RSA JWK key: %w
- key (k) is required
- invalid key type: %s
- invalid symmetric JWK: %w
- invalid EC JWK key: %w
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/69fcb3d9e4cbeb2b.
Report an issue: GitHub.