grafana/k6 · error
failed to decode first exponent: %w
Error message
failed to decode first exponent: %w
What it means
During RSA private-key JWK import, the CRT exponent dp (JWK field 'dp', exponent1) is decoded with base64.RawURLEncoding. This error indicates dp is not valid unpadded base64url: padding, '+'/'/' characters, whitespace, or bad length. Fields dq and qi have identical checks immediately after, so fixing encoding once usually resolves all three.
Source
Thrown at internal/js/modules/k6/webcrypto/jwk.go:370
if jwk.D == "" {
return pubKey, PublicCryptoKeyType, pubKey.N.BitLen(), nil
}
dBytes, err := base64URLDecode(jwk.D)
if err != nil {
return nil, UnknownCryptoKeyType, 0, fmt.Errorf("failed to decode private exponent: %w", err)
}
pBytes, err := base64URLDecode(jwk.P)
if err != nil {
return nil, UnknownCryptoKeyType, 0, fmt.Errorf("failed to decode first prime factor: %w", err)
}
qBytes, err := base64URLDecode(jwk.Q)
if err != nil {
return nil, UnknownCryptoKeyType, 0, fmt.Errorf("failed to decode second prime factor: %w", err)
}
dpBytes, err := base64URLDecode(jwk.Dp)
if err != nil {
return nil, UnknownCryptoKeyType, 0, fmt.Errorf("failed to decode first exponent: %w", err)
}
dqBytes, err := base64URLDecode(jwk.Dq)
if err != nil {
return nil, UnknownCryptoKeyType, 0, fmt.Errorf("failed to decode second exponent: %w", err)
}
qiBytes, err := base64URLDecode(jwk.Qi)
if err != nil {
return nil, UnknownCryptoKeyType, 0, fmt.Errorf("failed to decode coefficient: %w", err)
}
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{View on GitHub (pinned to 93accf6570)
Solutions
- Convert dp (and dq, qi) to unpadded base64url
- Strip whitespace and '=' padding from all CRT fields
- If CRT parameters are unavailable, note that k6's importer requires them for private RSA JWKs — obtain a complete JWK
- Validate all fields in one pass with a base64url regex before calling importKey
Example fix
// before
const jwk = { kty: 'RSA', n, e: 'AQAB', d, p, q, dp: paddedDp, dq: paddedDq, qi: paddedQi };
// after
const toB64u = (s) => s.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '').replace(/\s+/g, '');
const jwk = { kty: 'RSA', n, e: 'AQAB', d, p, q, dp: toB64u(paddedDp), dq: toB64u(paddedDq), qi: toB64u(paddedQi) }; Defensive patterns
Strategy: validation
Validate before calling
const B64URL = /^[A-Za-z0-9_-]+$/;
for (const f of ['dp', 'dq', 'qi']) {
if (jwk[f] !== undefined) {
const v = String(jwk[f]).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '').replace(/\s+/g, '');
if (!B64URL.test(v)) throw new Error(f + ' is not unpadded base64url');
jwk[f] = v;
}
} Type guard
function hasB64uCrtParams(jwk) {
const ok = (s) => typeof s === 'string' && /^[A-Za-z0-9_-]+$/.test(s);
return ok(jwk.dp) && ok(jwk.dq) && ok(jwk.qi);
} Try / catch
try {
key = await crypto.subtle.importKey('jwk', jwk, rsaAlg, true, usages);
} catch (e) {
if (e.message.includes('failed to decode first exponent')) {
jwk = { ...jwk, dp: toB64u(jwk.dp), dq: toB64u(jwk.dq), qi: toB64u(jwk.qi) };
key = await crypto.subtle.importKey('jwk', jwk, rsaAlg, true, usages);
} else throw e;
} Prevention
- Validate dp, dq and qi together — they share encoding and provenance
- Note that RSA private JWK import in k6 requires all CRT fields, unlike some libraries
- Run a one-shot base64url normalization over the whole JWK before import
When it happens
Trigger: dp in padded or standard base64; dp truncated; whitespace inside dp; a JWK that includes d/p/q but omits or mangles dp while still declaring a private key.
Common situations: Private JWKs from providers that use padded base64url; partial JWKs where CRT parameters were dropped or corrupted; values round-tripped through systems that alter padding.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to decode private exponent: %w
- failed to decode first prime factor: %w
- failed to decode second prime factor: %w
- failed to decode D: %w
- failed to decode modulus: %w
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/6e95feb33eb2c0cb.
Report an issue: GitHub.