grafana/k6 · error
failed to parse input as ECDH key: %w
Error message
failed to parse input as ECDH key: %w
What it means
importECDHJWK implements ECDH JWK import by first running the same ECDSA JWK parser, then converting the result to an ECDH key. This error is the wrapper around any failure of that first parsing stage, so its text ('failed to parse input as ECDH key') is generic; the specific cause (bad JSON, missing fields, bad crv, bad base64url) is in the wrapped %w chain. It is raised from crypto.subtle.importKey('jwk', ..., {name:'ECDH', namedCurve:...}).
Source
Thrown at internal/js/modules/k6/webcrypto/jwk.go:272
return pk, PublicCryptoKeyType, nil
}
d, err := base64URLDecode(jwkKey.D)
if err != nil {
return nil, UnknownCryptoKeyType, fmt.Errorf("failed to decode D: %w", err)
}
return &ecdsa.PrivateKey{
PublicKey: *pk,
D: new(big.Int).SetBytes(d),
}, PrivateCryptoKeyType, nil
}
func importECDHJWK(_ EllipticCurveKind, jsonKeyData []byte) (any, CryptoKeyType, error) {
// first we do try to parse the key as ECDSA key
key, _, err := importECDSAJWK(EllipticCurveKindP256, jsonKeyData)
if err != nil {
return nil, UnknownCryptoKeyType, fmt.Errorf("failed to parse input as ECDH key: %w", err)
}
switch key := key.(type) {
case *ecdsa.PrivateKey:
ecdhKey, err := key.ECDH()
if err != nil {
return nil, UnknownCryptoKeyType, fmt.Errorf("failed to convert ECDSA key to ECDH key: %w", err)
}
return ecdhKey, PrivateCryptoKeyType, nil
case *ecdsa.PublicKey:
ecdhKey, err := key.ECDH()
if err != nil {
return nil, UnknownCryptoKeyType, fmt.Errorf("failed to convert ECDSA key to ECDH key: %w", err)
}
return ecdhKey, PublicCryptoKeyType, nil
default:View on GitHub (pinned to 93accf6570)
Solutions
- Read the wrapped cause after 'failed to parse input as ECDH key:' to find the real failure
- Validate the JWK shape: kty 'EC', crv one of P-256/P-384/P-521, x/y present as unpadded base64url strings
- Pass the JWK as an object, not a JSON string
- Test the same JWK with {name:'ECDSA'} import to get the more specific error message, then fix that field
Example fix
// before
const key = await crypto.subtle.importKey('jwk', jwk, { name: 'ECDH', namedCurve: 'P-256' }, true, []); // generic failure
// after
// diagnose with the ECDSA importer to get the precise field error, fix it, then import as ECDH:
try { await crypto.subtle.importKey('jwk', jwk, { name: 'ECDSA', namedCurve: 'P-256' }, true, []); } catch (e) { console.log(e.message); }
const key = await crypto.subtle.importKey('jwk', fixedJwk, { name: 'ECDH', namedCurve: 'P-256' }, true, ['deriveKey', 'deriveBits']); Defensive patterns
Strategy: try-catch
Validate before calling
const B64URL = /^[A-Za-z0-9_-]+$/;
function isValidEcdhJwk(j) {
return j && typeof j === 'object' && j.kty === 'EC' &&
['P-256','P-384','P-521'].includes(j.crv) &&
typeof j.x === 'string' && B64URL.test(j.x) &&
typeof j.y === 'string' && B64URL.test(j.y) &&
(j.d === undefined || (typeof j.d === 'string' && B64URL.test(j.d)));
} Type guard
function isEcdhImportableJwk(j) {
return !!j && typeof j === 'object' && j.kty === 'EC' &&
['P-256','P-384','P-521'].includes(j.crv) &&
/^[A-Za-z0-9_-]+$/.test(j.x || '') && /^[A-Za-z0-9_-]+$/.test(j.y || '');
} Try / catch
try {
key = await crypto.subtle.importKey('jwk', jwk, { name: 'ECDH', namedCurve: jwk.crv }, true, ['deriveKey','deriveBits']);
} catch (e) {
if (e.message.includes('failed to parse input as ECDH key')) {
// wrapper hides the cause: re-run via the ECDSA importer for the specific field error
try { await crypto.subtle.importKey('jwk', jwk, { name: 'ECDSA', namedCurve: 'P-256' }, true, []); }
catch (e2) { throw new Error('ECDH JWK root cause: ' + e2.message); }
}
throw e;
} Prevention
- Remember ECDH JWK import reuses the ECDSA parser — fix everything the ECDSA path complains about
- Pre-validate the full EC JWK shape (kty, crv, x, y, optional d)
- Pass namedCurve consistent with the JWK's crv
When it happens
Trigger: Any of the ECDSA-parse failures occurring while importing with the ECDH algorithm: non-string fields, kty != 'EC', missing crv/x/y, crv outside P-256/P-384/P-521, or x/y/d not in unpadded base64url.
Common situations: Same real-world causes as the ECDSA parse errors (double-encoded JSON, padded base64url, non-canonical curve names), but seen through the ECDH code path where the generic message can mask which field is at fault.
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 convert ECDSA key to ECDH key: %w
- failed to convert ECDH key to ECDSA key: %w
- failed to parse input as EC JWK key: %w
- invalid EC JWK key: %w
- failed to parse elliptic curve: %w
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/50a4284814e41075.
Report an issue: GitHub.