{"record":{"id":"34b27e87bbcafe3e","repo":"grafana/k6","slug":"failed-to-extract-algorithm-w","errorCode":null,"errorMessage":"failed to extract algorithm: %w","messagePattern":"failed to extract algorithm: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/webcrypto/jwk.go","lineNumber":85,"sourceCode":"\n// exportSymmetricJWK exports a symmetric key as a map of JWK key parameters.\nfunc exportSymmetricJWK(key *CryptoKey) (*JsonWebKey, error) {\n\trawKey, ok := key.handle.([]byte)\n\tif !ok {\n\t\treturn nil, errors.New(\"key's handle isn't a byte slice\")\n\t}\n\n\t// wrap result into the object that is expected to be returned\n\texported := &JsonWebKey{}\n\n\texported.Set(\"k\", base64URLEncode(rawKey))\n\texported.Set(\"kty\", JWKOctKeyType)\n\texported.Set(\"ext\", key.Extractable)\n\texported.Set(\"key_ops\", key.Usages)\n\n\talgV, err := extractAlg(key.Algorithm, len(rawKey))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to extract algorithm: %w\", err)\n\t}\n\texported.Set(\"alg\", algV)\n\n\treturn exported, nil\n}\n\nfunc extractAlg(inAlg any, keyLen int) (string, error) {\n\tswitch alg := inAlg.(type) {\n\tcase hasHash:\n\t\tv := alg.hash()\n\t\tif len(v) < 4 {\n\t\t\treturn \"\", errors.New(\"length of hash algorithm is less than 4: \" + v)\n\t\t}\n\t\treturn \"HS\" + v[4:], nil\n\tcase hasAlg:\n\t\tv := alg.alg()\n\t\tif len(v) < 4 {\n\t\t\treturn \"\", errors.New(\"length of named algorithm is less than 4: \" + v)","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/webcrypto/jwk.go#L67-L103","documentation":"Thrown by k6 WebCrypto when exporting a symmetric key to JWK and the algorithm-to-'alg' mapping fails. exportSymmetricJWK (internal/js/modules/k6/webcrypto/jwk.go:83-86) calls extractAlg to derive the alg identifier (e.g. HS256 for HMAC/SHA-256, A256GCM for 256-bit AES-GCM); the wrapped inner error is one of: hash algorithm name shorter than 4 chars, named algorithm shorter than 4 chars, or 'unsupported algorithm'. This is essentially an internal consistency check — a well-formed key generated/imported through the normal API always carries a mappable algorithm.","triggerScenarios":"crypto.subtle.exportKey('jwk', symmetricKey) where the key's algorithm object was constructed through an unusual path — e.g. an imported raw key whose algorithm identifier got a truncated/nonstandard name, or a CryptoKey obtained from a nonstandard extension. Keys created by k6's own generateKey/importKey do not hit it.","commonSituations":"Interoperating with scripts that pass algorithm objects they built by hand (deep-cloning and mutating algorithm dictionaries); k6 version skew where a custom build changed algorithm names; extremely rare in vanilla k6 usage.","solutions":["As a workaround, export symmetric keys as 'raw' (base64url the bytes yourself) instead of 'jwk'.","Recreate the key through the standard path — generateKey or importKey('raw'|'jwk') with a canonical algorithm name — then export 'jwk' again.","If it reproduces with a normally-created key, file a k6 issue with the algorithm dictionary used."],"exampleFix":"// before\nconst jwk = await crypto.subtle.exportKey('jwk', key); // failed to extract algorithm\n\n// after\nconst raw = await crypto.subtle.exportKey('raw', key);\nconst jwk = { kty: 'oct', k: bytesToBase64url(new Uint8Array(raw)) };","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"let exported;\ntry {\n  exported = await crypto.subtle.exportKey('jwk', key);\n} catch (e) {\n  if (/failed to extract algorithm/.test(e.message)) {\n    const raw = await crypto.subtle.exportKey('raw', key);\n    exported = { kty: 'oct', k: bytesToBase64url(new Uint8Array(raw)) };\n  } else throw e;\n}","preventionTips":["Prefer 'raw' export for symmetric keys; 'jwk' adds an alg-mapping step that can fail.","Create keys only via generateKey/importKey with canonical algorithm names."],"tags":["webcrypto","jwk","export-key","algorithm"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}