{"record":{"id":"941cf24e1e28bee3","repo":"grafana/k6","slug":"failed-to-decode-coefficient-w","errorCode":null,"errorMessage":"failed to decode coefficient: %w","messagePattern":"failed to decode coefficient: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/webcrypto/jwk.go","lineNumber":378,"sourceCode":"\tpBytes, err := base64URLDecode(jwk.P)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, 0, fmt.Errorf(\"failed to decode first prime factor: %w\", err)\n\t}\n\tqBytes, err := base64URLDecode(jwk.Q)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, 0, fmt.Errorf(\"failed to decode second prime factor: %w\", err)\n\t}\n\tdpBytes, err := base64URLDecode(jwk.Dp)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, 0, fmt.Errorf(\"failed to decode first exponent: %w\", err)\n\t}\n\tdqBytes, err := base64URLDecode(jwk.Dq)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, 0, fmt.Errorf(\"failed to decode second exponent: %w\", err)\n\t}\n\tqiBytes, err := base64URLDecode(jwk.Qi)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, 0, fmt.Errorf(\"failed to decode coefficient: %w\", err)\n\t}\n\n\tprivKey := &rsa.PrivateKey{\n\t\tPublicKey: pubKey,\n\t\tD:         new(big.Int).SetBytes(dBytes),\n\t\tPrimes: []*big.Int{\n\t\t\tnew(big.Int).SetBytes(pBytes),\n\t\t\tnew(big.Int).SetBytes(qBytes),\n\t\t},\n\t\tPrecomputed: rsa.PrecomputedValues{\n\t\t\tDp:   new(big.Int).SetBytes(dpBytes),\n\t\t\tDq:   new(big.Int).SetBytes(dqBytes),\n\t\t\tQinv: new(big.Int).SetBytes(qiBytes),\n\t\t},\n\t}\n\n\terr = privKey.Validate()\n\tif err != nil {","sourceCodeStart":360,"sourceCodeEnd":396,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/webcrypto/jwk.go#L360-L396","documentation":"Thrown by k6's webcrypto RSA JWK importer when the 'qi' (q inverse, CRT coefficient) member of the imported JWK fails base64url decoding. Like the other CRT fields (dp, dq), qi is mandatory in k6's RSA private-key JWK path and must be unpadded RFC 7515 base64url; the wrapped error carries the exact decoding failure.","triggerScenarios":"crypto.subtle.importKey('jwk', jwk, rsaAlg, ...) with jwk.qi containing '+', '/', '=', whitespace, or a length that is not a multiple of 4 base64 chars. All earlier members (n, e, d, p, q, dp, dq) must decode successfully first, otherwise a different 'failed to decode ...' error is returned.","commonSituations":"Manually assembling a JWK from MPI/hex values produced by another crypto library without converting to base64url; truncating a long JWK line when copying; mixing up field order or pasting hex ('a1b2...') into qi; JWK tools that emit padded base64.","solutions":["Export a complete JWK from a working key via crypto.subtle.exportKey('jwk', key) and import that verbatim","Re-encode qi as unpadded base64url (translate '+'->'-', '/'->'_', drop '=' padding)","Pre-validate all JWK members with a base64url regex before calling importKey","Prefer PEM ('spki'/'pkcs8') import when you control the key serialization format"],"exampleFix":"// before\nconst priv = await crypto.subtle.importKey('jwk', exported, alg, true, ['sign']);\n// exported.qi is hex: '00aa11bb...'\n\n// after\nconst b64url = hexToB64Url(exported.qiHex); // encode bytes, then base64url without padding\nconst priv = await crypto.subtle.importKey('jwk', { ...exported, qi: b64url }, alg, true, ['sign']);","handlingStrategy":"validation","validationCode":"const b64url = s => s.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\nconst NEEDS_FIX = /[+/=]/;\nfor (const f of ['qi','dp','dq','p','q','d','n','e']) {\n  if (typeof jwk[f] === 'string' && NEEDS_FIX.test(jwk[f])) jwk[f] = b64url(jwk[f]);\n}\nawait crypto.subtle.importKey('jwk', jwk, alg, true, usages);","typeGuard":"const isB64Url = s => typeof s === 'string' && /^[A-Za-z0-9_-]*$/.test(s);\nconst hasValidQi = j => isB64Url(j.qi);","tryCatchPattern":"try { await crypto.subtle.importKey('jwk', jwk, alg, true, usages); }\ncatch (e) { if (/coefficient/.test(e.message)) console.error('fix jwk.qi encoding'); throw e; }","preventionTips":["Treat base64url normalization (drop '=', map '+'/'/') as a mandatory step for externally sourced JWKs","Validate every JWK member with a regex before import — cheap and pinpoints the field","Keep a canonical copy of keys produced by exportKey for tests"],"tags":["webcrypto","rsa","jwk","base64url","importkey"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}