grafana/k6 · error
failed to parse symmetric JWK: %w
Error message
failed to parse symmetric JWK: %w
What it means
Thrown by k6 WebCrypto when the JWK data passed to importKey('jwk', ...) for a symmetric algorithm cannot be parsed as JSON. extractSymmetricJWK (internal/js/modules/k6/webcrypto/jwk.go:50-54) runs json.Unmarshal on the serialized key data and wraps the encoding/json error verbatim (%w), so the tail of the message shows the exact JSON syntax problem (unexpected token, truncated document, etc.).
Source
Thrown at internal/js/modules/k6/webcrypto/jwk.go:53
}
func (jwk *symmetricJWK) validate() error {
if jwk.Kty != JWKOctKeyType {
return fmt.Errorf("invalid key type: %s", jwk.Kty)
}
if jwk.K == "" {
return errors.New("key (k) is required")
}
return nil
}
// extractSymmetricJWK extracts the symmetric key from a given JWK key (JSON data).
func extractSymmetricJWK(jsonKeyData []byte) ([]byte, error) {
sk := symmetricJWK{}
if err := json.Unmarshal(jsonKeyData, &sk); err != nil {
return nil, fmt.Errorf("failed to parse symmetric JWK: %w", err)
}
if err := sk.validate(); err != nil {
return nil, fmt.Errorf("invalid symmetric JWK: %w", err)
}
skBytes, err := base64URLDecode(sk.K)
if err != nil {
return nil, fmt.Errorf("failed to decode symmetric key: %w", err)
}
return skBytes, nil
}
// exportSymmetricJWK exports a symmetric key as a map of JWK key parameters.
func exportSymmetricJWK(key *CryptoKey) (*JsonWebKey, error) {
rawKey, ok := key.handle.([]byte)
if !ok {View on GitHub (pinned to 93accf6570)
Solutions
- Pass an actual JWK object (or a string that parses to one): { kty: 'oct', k: base64urlSecret }.
- If the source is a JSON file/response, JSON.parse it once before handing it to importKey.
- If all you have is a raw secret, import it as 'raw' format with the base64url-decoded bytes instead of jwk.
- Read the wrapped JSON error to find the offending token position.
Example fix
// before
await crypto.subtle.importKey('jwk', __ENV.SECRET_B64, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
// after
await crypto.subtle.importKey('raw', base64urlToBytes(__ENV.SECRET_B64), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']); Defensive patterns
Strategy: validation
Validate before calling
function parseJwk(maybeJson) {
const obj = typeof maybeJson === 'string' ? JSON.parse(maybeJson) : maybeJson;
if (obj == null || typeof obj !== 'object') throw new Error('JWK input is not an object');
return obj;
} Type guard
const looksLikeJwk = (v) => { try { const o = typeof v === 'string' ? JSON.parse(v) : v; return !!o && typeof o === 'object' && 'kty' in o; } catch { return false; } }; Try / catch
try { await crypto.subtle.importKey('jwk', keyData, alg, false, usages); } catch (e) { if (/failed to parse symmetric JWK/.test(e.message)) { const parsed = JSON.parse(keyData); return crypto.subtle.importKey('jwk', parsed, alg, false, usages); } throw e; } Prevention
- JSON.parse fetched key material exactly once before importKey.
- For raw secrets, use 'raw' format rather than fabricating JWK JSON.
When it happens
Trigger: Passing a raw base64 secret, a PEM string, or a double-stringified JSON string instead of a JWK object; a JWK JSON file with a trailing comma or truncation; passing the result of JSON.stringify twice so the parser sees a string document where an object is expected.
Common situations: Copy-pasting an opaque shared secret from a vault into the jwk parameter; fetch() of a key endpoint returning text that was never JSON.parse'd; hand-editing a JWK fixture and breaking syntax.
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
- invalid key type: %s
- invalid symmetric JWK: %w
- failed to decode symmetric key: %w
- failed to parse input as EC JWK key: %w
- failed to parse input as RSA JWK key: %w
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/c0b0189813586389.
Report an issue: GitHub.