{"record":{"id":"5cd6abffe6010966","repo":"grafana/k6","slug":"failed-to-decode-d-w","errorCode":null,"errorMessage":"failed to decode D: %w","messagePattern":"failed to decode D: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/webcrypto/jwk.go","lineNumber":259,"sourceCode":"\ty, err := base64URLDecode(jwkKey.Y)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, fmt.Errorf(\"failed to decode Y coordinate: %w\", err)\n\t}\n\n\tpk := &ecdsa.PublicKey{\n\t\tCurve: crv,\n\t\tX:     new(big.Int).SetBytes(x),\n\t\tY:     new(big.Int).SetBytes(y),\n\t}\n\n\t// if the key is a public key, return it\n\tif jwkKey.D == \"\" {\n\t\treturn pk, PublicCryptoKeyType, nil\n\t}\n\n\td, err := base64URLDecode(jwkKey.D)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, fmt.Errorf(\"failed to decode D: %w\", err)\n\t}\n\n\treturn &ecdsa.PrivateKey{\n\t\tPublicKey: *pk,\n\t\tD:         new(big.Int).SetBytes(d),\n\t}, PrivateCryptoKeyType, nil\n}\n\nfunc importECDHJWK(_ EllipticCurveKind, jsonKeyData []byte) (any, CryptoKeyType, error) {\n\t// first we do try to parse the key as ECDSA key\n\tkey, _, err := importECDSAJWK(EllipticCurveKindP256, jsonKeyData)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, fmt.Errorf(\"failed to parse input as ECDH key: %w\", err)\n\t}\n\n\tswitch key := key.(type) {\n\tcase *ecdsa.PrivateKey:\n\t\tecdhKey, err := key.ECDH()","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/webcrypto/jwk.go#L241-L277","documentation":"When the EC JWK contains a non-empty d field it is treated as a private key, and d (the private scalar) is decoded with base64.RawURLEncoding. This error means d is not valid unpadded base64url — padding characters, wrong alphabet, whitespace, or bad length. It is returned from crypto.subtle.importKey('jwk', ...) for ECDSA.","triggerScenarios":"d contains '=' padding, '+' or '/' characters, or whitespace; d truncated or copied incompletely; d supplied as a number instead of a string would instead fail earlier at JSON unmarshal.","commonSituations":"Private scalars emitted with padded base64url by external key stores; hand-assembled JWKs where d came from a hex or PEM representation; secret-management systems that re-encode values.","solutions":["Convert d to unpadded base64url before import","Check the decoded scalar length does not exceed the curve size (32/48/66 bytes for P-256/P-384/P-521)","Remove the d field entirely if you only need the public key (import then returns a public CryptoKey)","Re-export the JWK from the originating system with strict base64url encoding"],"exampleFix":"// before\nconst jwk = { kty: 'EC', crv: 'P-256', x, y, d: paddedD };\n// after\nconst toB64u = (s) => s.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '').trim();\nconst jwk = { kty: 'EC', crv: 'P-256', x, y, d: toB64u(paddedD) };","handlingStrategy":"validation","validationCode":"const B64URL = /^[A-Za-z0-9_-]+$/;\nif (jwk.d !== undefined && jwk.d !== '') {\n  const d = String(jwk.d).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '').trim();\n  if (!B64URL.test(d)) throw new Error('d is not valid unpadded base64url');\n  jwk = { ...jwk, d };\n}","typeGuard":"function isB64uScalar(s) {\n  return typeof s === 'string' && /^[A-Za-z0-9_-]+$/.test(s) && s.length % 4 !== 1;\n}","tryCatchPattern":"try {\n  key = await crypto.subtle.importKey('jwk', jwk, alg, true, usages);\n} catch (e) {\n  if (e.message.includes('failed to decode D')) {\n    jwk = { ...jwk, d: toB64u(jwk.d) };\n    key = await crypto.subtle.importKey('jwk', jwk, alg, true, usages);\n  } else throw e;\n}","preventionTips":["Treat d like x/y: unpadded base64url only","If you only need verify/encrypt operations, remove d to import a public key","Store private JWKs verbatim from the exporting system; do not re-encode by hand"],"tags":["webcrypto","jwk","import","ecdsa","base64url","private-key","k6"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}