denoland/deno · error · TypeError

Algorithm must be specified when using non-Ed25519 keys

Error message

Algorithm must be specified when using non-Ed25519 keys

What it means

One-shot crypto.sign() with a non-Ed25519/Ed448 key requires an explicit digest. The only default is an rsa-pss key whose stored key details include a hashAlgorithm; for every other key type (rsa, ecdsa, dsa, rsa-pss without an embedded hash) algorithm == null throws this TypeError.

Source

Thrown at ext/node/polyfills/internal/crypto/sig.ts:439

      if (
        ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, ctx) &&
        ctx.length > 0
      ) {
        throw new TypeError("Context parameter is unsupported");
      }
      result = new FastBuffer(114);
      op_node_sign_ed448(handle, dataBytes, result);
    } else {
      let digest = algorithm;
      if (digest == null) {
        if (keyType === "rsa-pss") {
          const details = op_node_get_asymmetric_key_details(handle);
          if (details.hashAlgorithm) {
            digest = details.hashAlgorithm;
          }
        }
        if (digest == null) {
          throw new TypeError(
            "Algorithm must be specified when using non-Ed25519 keys",
          );
        }
      }
      // Preserve padding/saltLength options from the original key
      const privateKeyObject = new PrivateKeyObject(handle);
      const signKey = typeof key === "object" &&
          !(ObjectPrototypeIsPrototypeOf(KeyObject.prototype, key))
        ? { ...key, key: privateKeyObject }
        : privateKeyObject;
      result = Sign(digest).update(dataBytes)
        .sign(signKey);
    }

    if (callback) {
      setTimeout(() => callback(null, result));
    } else {
      return result;

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Pass an explicit digest: crypto.sign("sha256", data, key).
  2. Branch by key.asymmetricKeyType — null only for ed25519/ed448 (and rsa-pss with embedded hash).
  3. When generating rsa-pss keys, set hashAlgorithm so the embedded default applies.

Example fix

// before
const sig = crypto.sign(null, data, key); // throws for RSA/ECDSA keys

// after
const alg = key.asymmetricKeyType === "ed25519" || key.asymmetricKeyType === "ed448" ? null : "sha256";
const sig = crypto.sign(alg, data, key);
Defensive patterns

Strategy: validation

Validate before calling

function requiredDigest(key, requested) {
  if (requested != null) return requested;
  const t = key.asymmetricKeyType ?? key.key?.asymmetricKeyType;
  if (t === "ed25519" || t === "ed448") return null;
  throw new Error(`an explicit digest (e.g. "sha256") is required for ${t} keys`);
}
const sig = crypto.sign(requiredDigest(key, alg), data, key);

Type guard

const needsExplicitDigest = (key) => {
  const t = key.asymmetricKeyType ?? key.key?.asymmetricKeyType;
  return t !== "ed25519" && t !== "ed448" && t !== "rsa-pss"; // rsa-pss may carry its own hash
};

Try / catch

try {
  sig = crypto.sign(digest, data, key);
} catch (e) {
  if (e instanceof TypeError && /Algorithm must be specified/.test(e.message)) {
    throw new Error(`digest required for key type ${key.asymmetricKeyType}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: crypto.sign(null, data, rsaPrivateKey); crypto.sign(null, data, ecdsaKey); copy-pasted ed25519 example code (which passes null) reused with RSA or EC keys.

Common situations: Key-agnostic signing helpers that pass null because it works for ed25519; code written against rsa-pss keys with embedded hashes then pointed at plain RSA keys; WebCrypto ports where the hash was part of the key rather than the call.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/0b94b6ec668003a6. Report an issue: GitHub.