denoland/deno · error · Error
ERR_CRYPTO_SIGN_KEY_REQUIRED
ERR_CRYPTO_SIGN_KEY_REQUIRED
Error message
No key provided to sign
What it means
Thrown by Sign.sign(privateKey) (the object returned by crypto.createSign(digest)) when the first argument is falsy. The Sign object only accumulates the data to be signed; the private key must be supplied at sign() time as a KeyObject, PEM string, or an options object such as { key, passphrase }. This mirrors Node's ERR_CRYPTO_SIGN_KEY_REQUIRED behavior.
Source
Thrown at ext/node/polyfills/internal/crypto/sig.ts:168
},
});
algorithm = StringPrototypeToLowerCase(algorithm);
this.#digestType = algorithm;
try {
this.hash = createHash(this.#digestType);
} catch {
throw new Error(`Invalid digest: ${algorithm}`);
}
}
sign(
privateKey: any,
encoding?: any,
): Buffer | string {
if (!privateKey) {
throw new ERR_CRYPTO_SIGN_KEY_REQUIRED();
}
const res = prepareAsymmetricKey(privateKey, kConsumePrivate);
// Options specific to RSA
const rsaPadding = getPadding(privateKey);
// Options specific to RSA-PSS
const pssSaltLength = getSaltLength(privateKey);
// Options specific to (EC)DSA
const dsaSigEnc = getDSASignatureEncoding(privateKey);
let handle;
if (ReflectHas(res, "handle")) {
handle = res.handle;
} else {
try {View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Pass the private key as the first argument to sign(): a KeyObject from createPrivateKey(), a PEM string, or { key, passphrase } for encrypted PEMs.
- If the key comes from an env var or file, fail fast with a clear error when loading returns empty instead of forwarding undefined.
- Materialize and validate the key once at startup with crypto.createPrivateKey(pem) so bad key material surfaces immediately.
Example fix
// before
const signer = crypto.createSign("sha256");
signer.update(payload);
const sig = signer.sign(process.env.PRIVATE_KEY); // env unset -> ERR_CRYPTO_SIGN_KEY_REQUIRED
// after
const key = crypto.createPrivateKey(fs.readFileSync("private.pem")); // fails loudly if the key is bad
const sig = crypto.createSign("sha256").update(payload).sign(key); Defensive patterns
Strategy: validation
Validate before calling
const keyPem = fs.readFileSync("private.pem", "utf8");
if (!keyPem || !keyPem.includes("PRIVATE KEY")) {
throw new Error("private.pem missing or not a private key");
}
const key = crypto.createPrivateKey(keyPem); // also validates the material
const sig = crypto.createSign("sha256").update(data).sign(key); Type guard
function isSignKeyInput(k) {
if (!k) return false;
if (typeof k === "string" || k instanceof crypto.KeyObject) return true;
return typeof k === "object" && (typeof k.key === "string" || k.key instanceof crypto.KeyObject);
} Try / catch
try {
sig = signer.sign(key);
} catch (e) {
if (e?.code === "ERR_CRYPTO_SIGN_KEY_REQUIRED") {
throw new Error("Signing aborted: private key was not provided or failed to load");
}
throw e;
} Prevention
- Materialize keys once at startup with createPrivateKey so missing/bad material fails immediately, not at first signature.
- Never pass env vars directly into sign() — read and validate them first.
- For passphrase-protected PEMs pass { key, passphrase } and check both fields.
When it happens
Trigger: crypto.createSign("sha256").update(data).sign(undefined); sign.sign(null); sign.sign() with no arguments; key read from an env var or JSON config that was missing so the destructured variable is undefined.
Common situations: PRIVATE_KEY env var unset in a deploy environment; PEM file read failed silently and produced undefined; refactor renamed the key variable so an old name is passed; migration from one-shot crypto.sign() to the streaming API where the key argument was dropped.
Related errors
- operation not supported for this keytype
- ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY
- Failed to get ECDH private key
- Failed to get ECDH public key
- ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/05e307fee50fcc2a.
Report an issue: GitHub.