grafana/k6 · error

failed to convert ECDH key to ECDSA key: %w

Error message

failed to convert ECDH key to ECDSA key: %w

What it means

k6's WebCrypto implementation stores ECDH keys internally as Go *ecdh.PrivateKey handles, but the JWK exporter (exportECJWK in internal/js/modules/k6/webcrypto/jwk.go) only serializes ECDSA-shaped keys, so it first converts the ECDH key via convertECDHtoECDSAKey. This error means that conversion failed, and it is raised from crypto.subtle.exportKey('jwk', key). The underlying cause is either an unsupported curve (only P-256/P-384/P-521 map to ECDSA curves) or a public point that cannot be unmarshaled onto the ECDSA curve.

Source

Thrown at internal/js/modules/k6/webcrypto/jwk.go:188

	exported.Set("kty", JWKECKeyType)

	var x, y, d *big.Int
	var curveParams *elliptic.CurveParams

	switch k := key.handle.(type) {
	case *ecdsa.PrivateKey:
		x = k.X
		y = k.Y
		d = k.D
		curveParams = k.Params()
	case *ecdsa.PublicKey:
		x = k.X
		y = k.Y
		curveParams = k.Params()
	case *ecdh.PrivateKey:
		ecdsaKey, err := convertECDHtoECDSAKey(k)
		if err != nil {
			return nil, fmt.Errorf("failed to convert ECDH key to ECDSA key: %w", err)
		}

		x = ecdsaKey.X
		y = ecdsaKey.Y
		d = ecdsaKey.D
		curveParams = ecdsaKey.Params()
	case *ecdh.PublicKey:
		ecdsaKey, err := convertPublicECDHtoECDSA(k)
		if err != nil {
			return nil, fmt.Errorf("failed to convert ECDH key to ECDSA key: %w", err)
		}

		x = ecdsaKey.X
		y = ecdsaKey.Y
		curveParams = ecdsaKey.Params()
	default:
		return nil, errors.New("key's handle isn't an ECDSA/ECDH public/private key")
	}

View on GitHub (pinned to 93accf6570)

Solutions

  1. Confirm the key was generated/imported with namedCurve 'P-256', 'P-384' or 'P-521'
  2. Re-generate the key pair with crypto.subtle.generateKey({name:'ECDH', namedCurve:'P-256'}, ...) and export the new key
  3. Fall back to exporting in 'raw' (public), 'spki' (public) or 'pkcs8' (private) format, which do not use the ECDSA conversion
  4. If the key came from generateKey with a supported curve, report it as a k6 bug at https://github.com/grafana/k6/issues including the curve and import path used

Example fix

// before
const jwk = await crypto.subtle.exportKey('jwk', ecdhPrivKey); // throws: failed to convert ECDH key to ECDSA key

// after
const raw = new Uint8Array(await crypto.subtle.exportKey('pkcs8', ecdhPrivKey));
// or regenerate with a supported curve:
const pair = await crypto.subtle.generateKey({ name: 'ECDH', namedCurve: 'P-256' }, true, ['deriveKey', 'deriveBits']);
const jwk2 = await crypto.subtle.exportKey('jwk', pair.privateKey);
Defensive patterns

Strategy: try-catch

Validate before calling

const SUPPORTED = ['P-256', 'P-384', 'P-521'];
function canExportEcdhJwk(key) {
  return key.algorithm && key.algorithm.name === 'ECDH' &&
         SUPPORTED.includes(key.algorithm.namedCurve);
}

Type guard

function isExportableEcdhKey(key) {
  return key && key.algorithm && key.algorithm.name === 'ECDH' &&
    ['P-256', 'P-384', 'P-521'].includes(key.algorithm.namedCurve) &&
    typeof key.extract === 'function';
}

Try / catch

try {
  const jwk = await crypto.subtle.exportKey('jwk', ecdhPriv);
} catch (e) {
  if (e.message.includes('failed to convert ECDH key to ECDSA key')) {
    const pkcs8 = await crypto.subtle.exportKey('pkcs8', ecdhPriv); // fallback format
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling crypto.subtle.exportKey('jwk', ecdhPrivateKey) where the key handle's curve is not P-256, P-384 or P-521, or where the stored key bytes are not a valid point on the curve (corrupted handle). The error is wrapped around the converter's own error ('curve not supported for converting to ECDSA key' or 'unable to convert ECDH public key to ECDSA public key').

Common situations: Exporting an ECDH key that was generated or imported outside the supported NIST curves; keys whose material was mutated between import and export; edge-case k6 versions where the ECDH handle was constructed inconsistently. Rare in practice because import paths validate the point, so hitting it usually indicates an internal inconsistency.

Related errors


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/8df931a744473bab. Report an issue: GitHub.