grafana/k6 · error

failed to decode Y coordinate: %w

Error message

failed to decode Y coordinate: %w

What it means

The y coordinate is decoded with base64.RawURLEncoding (unpadded base64url), exactly like x. This error indicates the y string is not valid unpadded base64url — padded values, standard base64 alphabet characters, embedded whitespace, or an impossible length. It surfaces from crypto.subtle.importKey('jwk', ...) for ECDSA.

Source

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

	}

	if err := jwkKey.validate(); err != nil {
		return nil, UnknownCryptoKeyType, fmt.Errorf("invalid EC JWK key: %w", err)
	}

	crv, err := pickEllipticCurve(jwkKey.Crv)
	if err != nil {
		return nil, UnknownCryptoKeyType, fmt.Errorf("failed to parse elliptic curve: %w", err)
	}

	x, err := base64URLDecode(jwkKey.X)
	if err != nil {
		return nil, UnknownCryptoKeyType, fmt.Errorf("failed to decode X coordinate: %w", err)
	}

	y, err := base64URLDecode(jwkKey.Y)
	if err != nil {
		return nil, UnknownCryptoKeyType, fmt.Errorf("failed to decode Y coordinate: %w", err)
	}

	pk := &ecdsa.PublicKey{
		Curve: crv,
		X:     new(big.Int).SetBytes(x),
		Y:     new(big.Int).SetBytes(y),
	}

	// if the key is a public key, return it
	if jwkKey.D == "" {
		return pk, PublicCryptoKeyType, nil
	}

	d, err := base64URLDecode(jwkKey.D)
	if err != nil {
		return nil, UnknownCryptoKeyType, fmt.Errorf("failed to decode D: %w", err)
	}

View on GitHub (pinned to 93accf6570)

Solutions

  1. Convert y to unpadded base64url (replace '+'->'-', '/'->'_', strip trailing '=')
  2. Remove any whitespace or line breaks embedded in the value
  3. Confirm the decoded length matches the curve size (32/48/66 bytes for P-256/P-384/P-521)
  4. Regenerate the JWK from the source key with a base64url-without-padding encoder

Example fix

// before
const jwk = { kty: 'EC', crv: 'P-256', x: b64uX, y: paddedY };
// after
const toB64u = (s) => s.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '').trim();
const jwk = { kty: 'EC', crv: 'P-256', x: b64uX, y: toB64u(paddedY) };
Defensive patterns

Strategy: validation

Validate before calling

const B64URL = /^[A-Za-z0-9_-]+$/;
const toB64u = (s) => String(s).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '').trim();
const y = toB64u(jwk.y);
if (!B64URL.test(y) || y.length < 2) throw new Error('y is not valid unpadded base64url');

Type guard

function isB64uCoord(s) {
  return typeof s === 'string' && /^[A-Za-z0-9_-]+$/.test(s) && s.length % 4 !== 1;
}

Try / catch

try {
  key = await crypto.subtle.importKey('jwk', jwk, alg, true, usages);
} catch (e) {
  if (e.message.includes('failed to decode Y coordinate')) {
    jwk = { ...jwk, y: toB64u(jwk.y) };
    key = await crypto.subtle.importKey('jwk', jwk, alg, true, usages);
  } else throw e;
}

Prevention

When it happens

Trigger: y contains '=', '+', '/', or whitespace; y was truncated during copy-paste; y re-encoded with a padded variant by an upstream service.

Common situations: Same class of issues as x: toolchains emitting padded base64url, PEM-derived values, or manual transcription. y is frequently mangled because it is the last field and trailing '=' padding is common.

Understand the failure class

Related errors


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