Error message
NotSupportedError: Unrecognized algorithm name
Node's wording; Node also reports "Unrecognized namedCurve" for unknown curves. Chrome prints the terser "Unrecognized name." — the DOMException name NotSupportedError is the stable part.
WebCrypto crypto.subtle — browsers & Node
What it means
The algorithm (or curve) you named is not one this WebCrypto implementation offers. Either the identifier has a typo, or you asked for something genuinely outside the standard set — most commonly secp256k1, which WebCrypto does not include despite being an EC curve like the P-* family. The check runs before any key material is touched, so the identical call succeeds once the name is corrected.
Why it happens
secp256k1 requested from WebCrypto
commonBitcoin/Ethereum code often assumes namedCurve: "secp256k1" will work like P-256. It never has: the WebCrypto registry covers P-256, P-384 and P-521 only. (Node's non-WebCrypto crypto module does support secp256k1.)
JWT-style names used as algorithm names
common"ES256", "RS256" or "ECDSA_P256_SHA256" are JOSE/other-ecosystem identifiers. WebCrypto wants { name: "ECDSA", namedCurve: "P-256" } for keys and { name: "ECDSA", hash: "SHA-256" } for operations.
Newer algorithms on older runtimes
occasionalEd25519/X25519 landed in WebCrypto across 2023–2025; older browsers, Node versions and some WebViews still reject them. Feature-detect before relying on them.
How to fix it
- 1.
Use the exact WebCrypto identifiers
Names are matched case-insensitively but must be the registered ones — and curve names are exact. Note the two dictionaries: generateKey/importKey take namedCurve, while sign/verify take hash; mixing them up is its own flavor of this error.
js const key = await crypto.subtle.generateKey( { name: "ECDSA", namedCurve: "P-256" }, // not "ES256", not "secp256r1" false, ["sign", "verify"], ); const sig = await crypto.subtle.sign({ name: "ECDSA", hash: "SHA-256" }, key.privateKey, data); - 2.
For secp256k1, use a library
In browsers, an audited pure-JS implementation is the standard route; in Node, the built-in (non-WebCrypto) crypto module handles the curve natively, so server code has two options.
js // browser: @noble/curves (audited, dependency-free) import { secp256k1 } from "@noble/curves/secp256k1"; const ok = secp256k1.verify(signature, msgHash, publicKey); // node: built-in crypto.generateKeyPairSync("ec", { namedCurve: "secp256k1" });