denoland/deno · error · ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS

ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS

ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS

Error message

The selected key encoding ${typeStr} can only be used for RSA keys.

What it means

In key-pair encoding options, type 'pkcs1' is an RSA-only encoding. parseKeyType (ext/node/polyfills/internal/crypto/keygen.ts:235-244) checks the keyType it was given and, when the pair being generated is anything other than 'rsa', throws ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS ('can only be used for RSA keys'). pkcs1 (RFC 8017) defines RSA public/private key syntax, so this is a structural mismatch, not a preference.

Source

Thrown at ext/node/polyfills/internal/crypto/keygen.ts:240

    return "der";
  } else if (formatStr === "jwk") {
    return "jwk";
  }
  throw new ERR_INVALID_ARG_VALUE(optionName, formatStr);
}

function parseKeyType(
  typeStr: string | undefined,
  required: boolean,
  keyType: string | undefined,
  isPublic: boolean | undefined,
  optionName: string,
): string | undefined {
  if (typeStr === undefined && !required) {
    return undefined;
  } else if (typeStr === "pkcs1") {
    if (keyType !== undefined && keyType !== "rsa") {
      throw new ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(
        typeStr,
        "can only be used for RSA keys",
      );
    }
    return "pkcs1";
  } else if (typeStr === "spki" && isPublic !== false) {
    return "spki";
  } else if (typeStr === "pkcs8" && isPublic !== true) {
    return "pkcs8";
  } else if (typeStr === "sec1" && isPublic !== true) {
    if (keyType !== undefined && keyType !== "ec") {
      throw new ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(
        typeStr,
        "can only be used for EC keys",
      );
    }
    return "sec1";
  }

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. For EC keys use type 'sec1' (private) / 'spki' (public); for Ed25519 and most private keys use 'pkcs8'.
  2. Make the encoding type follow the algorithm in config: rsa->pkcs1, ec->sec1, everything else->pkcs8/spki.
  3. Drop the type option entirely where a safe default exists for your format.

Example fix

// before
crypto.generateKeyPairSync('ed25519', {
  privateKeyEncoding: { type: 'pkcs1', format: 'pem' }, // pkcs1 is RSA-only
});

// after
crypto.generateKeyPairSync('ed25519', {
  privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
});
Defensive patterns

Strategy: validation

Validate before calling

const PRIVATE_TYPE_BY_ALG = {
  rsa: 'pkcs1', 'rsa-pss': 'pkcs8', ec: 'sec1', ed25519: 'pkcs8', dsa: 'pkcs8',
};
const enc = { format: 'pem', type: PRIVATE_TYPE_BY_ALG[alg] };
if (enc.type === 'pkcs1' && alg !== 'rsa') {
  throw new Error(`pkcs1 cannot encode ${alg} keys`);
}

Type guard

function privateKeyTypeFor(alg) {
  if (alg === 'rsa') return 'pkcs1';
  if (alg === 'ec') return 'sec1';
  return 'pkcs8'; // safe default for ed25519, rsa-pss, dsa, ...
}

Try / catch

try {
  crypto.generateKeyPairSync(alg, { privateKeyEncoding: { type: 'pkcs1', format: 'pem' } });
} catch (e) {
  if (e.code === 'ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS') {
    return crypto.generateKeyPairSync(alg, {
      privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
    });
  }
  throw e;
}

Prevention

When it happens

Trigger: generateKeyPairSync('ed25519' | 'ec' | 'dsa' | 'rsa-pss', { privateKeyEncoding: { type: 'pkcs1', format: 'pem' } }); reusing an RSA-oriented encoding config for every key type in a multi-algorithm service.

Common situations: Copy-pasting an options block between RSA and EC/Ed25519 generators; config templates with a fixed privateKeyEncoding.type; wrapping generateKeyPairSync behind a generic helper that ignores the algorithm when building encoding options.

Related errors


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