{"record":{"id":"e93f841fc41abdce","repo":"grafana/k6","slug":"key-k-is-required","errorCode":null,"errorMessage":"key (k) is required","messagePattern":"key \\(k\\) is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/webcrypto/jwk.go","lineNumber":43,"sourceCode":"// Set sets a key-value pair in the JWK.\nfunc (jwk *JsonWebKey) Set(key string, value any) {\n\t(*jwk)[key] = value\n}\n\n// symmetricJWK represents a symmetric JWK key.\n// It is used to unmarshal symmetric keys from JWK format.\ntype symmetricJWK struct {\n\tKty string `json:\"kty\"`\n\tK   string `json:\"k\"`\n}\n\nfunc (jwk *symmetricJWK) validate() error {\n\tif jwk.Kty != JWKOctKeyType {\n\t\treturn fmt.Errorf(\"invalid key type: %s\", jwk.Kty)\n\t}\n\n\tif jwk.K == \"\" {\n\t\treturn errors.New(\"key (k) is required\")\n\t}\n\n\treturn nil\n}\n\n// extractSymmetricJWK extracts the symmetric key from a given JWK key (JSON data).\nfunc extractSymmetricJWK(jsonKeyData []byte) ([]byte, error) {\n\tsk := symmetricJWK{}\n\tif err := json.Unmarshal(jsonKeyData, &sk); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse symmetric JWK: %w\", err)\n\t}\n\n\tif err := sk.validate(); err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid symmetric JWK: %w\", err)\n\t}\n\n\tskBytes, err := base64URLDecode(sk.K)\n\tif err != nil {","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/webcrypto/jwk.go#L25-L61","documentation":"When importing a symmetric (octet, kty='oct') key from JWK via crypto.subtle.importKey, k6 unmarshals it into symmetricJWK and validates it (internal/js/modules/k6/webcrypto/jwk.go:37). The `k` member holds the base64url-encoded key material; if it is missing or an empty string, validate() returns \"key (k) is required\". (A wrong kty produces the separate \"invalid key type\" error.)","triggerScenarios":"`crypto.subtle.importKey('jwk', { kty: 'oct', alg: 'A256GCM' }, ...)` — a JWK with no `k` field or `k: ''`. Common with hand-written or template JWKs where only the algorithm identifier was filled in.","commonSituations":"Building JWKs from configuration that forgot the key material; copying JWK examples and replacing alg but not k; string-building JSON where the k value ends up empty; secret-management code that injects the key under a different property name.","solutions":["Include the base64url-encoded key material: { kty: 'oct', alg: 'A128GCM', k: base64urlKey }","Verify programmatically that the JWK has a non-empty k before calling importKey","Check how the JWK was serialized — a mismatched property name (e.g. 'key') silently drops k"],"exampleFix":"// before\nconst jwk = { kty: 'oct', alg: 'A256GCM' }; // no key material\nconst key = await crypto.subtle.importKey('jwk', jwk, { name: 'AES-GCM' }, true, ['encrypt']);\n\n// after (base64url of the raw 32 bytes, no padding)\nconst jwk = { kty: 'oct', alg: 'A256GCM', k: 'RxS6T4LZf0p1O2n3M4q5R6s7T8u9V0w1X2y3Z4a5B6c' };\nconst key = await crypto.subtle.importKey('jwk', jwk, { name: 'AES-GCM' }, true, ['encrypt']);","handlingStrategy":"validation","validationCode":"const parsed = typeof jwk === 'string' ? JSON.parse(jwk) : jwk;\nif (parsed.kty === 'oct' && (typeof parsed.k !== 'string' || parsed.k.length === 0)) {\n  throw new Error('symmetric JWK is missing the k (key material) member');\n}","typeGuard":"const isValidSymmetricJWK = (j) => j.kty === 'oct' && typeof j.k === 'string' && j.k.length > 0;","tryCatchPattern":"try {\n  key = await crypto.subtle.importKey('jwk', jwk, alg, true, usages);\n} catch (e) {\n  if (String(e.message).includes('key (k) is required')) throw new Error('JWK has no key material — check how it was built/serialized');\n  throw e;\n}","preventionTips":["Always include k (base64url, no padding) in oct JWKs","Validate JWKs with a schema check before importKey","Watch for property-name drift (k vs key) when building JWKs from config or secret stores"],"tags":["webcrypto","jwk","import","validation","key-management"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}