denoland/deno · error · NodeTypeError
ERR_TLS_PROTOCOL_VERSION_CONFLICT
ERR_TLS_PROTOCOL_VERSION_CONFLICT
Error message
TLS protocol version ${options.minVersion || options.maxVersion} conflicts with secureProtocol secureProtocol What it means
getProtocolRange resolves the TLS version range from options. If options.secureProtocol is set (the legacy OpenSSL method-string API) and minVersion or maxVersion is also set, the two mechanisms conflict and it throws ERR_TLS_PROTOCOL_VERSION_CONFLICT before the method string is even validated - exactly Node's ordering.
Source
Thrown at ext/node/polyfills/_tls_common.ts:297
return ArrayPrototypeFilter(
ArrayPrototypeMap(val, (v: any) => toStringOrUndefined(v)!),
Boolean,
);
}
return toStringOrUndefined(val);
}
function getProtocolRange(
options: any,
): { minVersion: string; maxVersion: string } {
let minVersion = getDefaultMinVersion();
let maxVersion = getDefaultMaxVersion();
if (options.secureProtocol) {
// If secureProtocol is set, minVersion/maxVersion must not also be set.
// Node raises this conflict before validating the protocol method string.
if (options.minVersion || options.maxVersion) {
throw new ERR_TLS_PROTOCOL_VERSION_CONFLICT(
options.minVersion || options.maxVersion,
"secureProtocol",
);
}
const range = kProtocolMap[options.secureProtocol];
if (!range) {
if (
options.secureProtocol === "SSLv2_method" ||
options.secureProtocol === "SSLv2_client_method" ||
options.secureProtocol === "SSLv2_server_method"
) {
throw new ERR_TLS_INVALID_PROTOCOL_METHOD("SSLv2 methods disabled");
}
if (
options.secureProtocol === "SSLv3_method" ||
options.secureProtocol === "SSLv3_client_method" ||
options.secureProtocol === "SSLv3_server_method"View on GitHub (pinned to 89f33cbef2)
Solutions
- Delete secureProtocol and keep minVersion/maxVersion (the modern API)
- Or keep secureProtocol alone and remove minVersion/maxVersion
- Normalize merged option objects so the legacy field never survives alongside version pins
- Standardize new code on minVersion: 'TLSv1.2' style
Example fix
// before
const opts = {
secureProtocol: 'TLSv1_2_method',
minVersion: 'TLSv1.2', // conflict -> throws
};
// after
const opts = { minVersion: 'TLSv1.2', maxVersion: 'TLSv1.3' }; Defensive patterns
Strategy: validation
Validate before calling
function normalizeTlsOptions(o) {
if (o.secureProtocol && (o.minVersion || o.maxVersion)) {
delete o.secureProtocol; // modern version knobs win
}
return o;
} Try / catch
try {
sock = new tls.TLSSocket(s, opts);
} catch (e) {
if (e.code === 'ERR_TLS_PROTOCOL_VERSION_CONFLICT') {
const { secureProtocol, ...rest } = opts;
sock = new tls.TLSSocket(s, rest);
} else throw e;
} Prevention
- Pick one TLS-version API per codebase and lint for the other
- Deep-merge TLS configs consciously; log when legacy secureProtocol is dropped
- Pin versions via minVersion/maxVersion, not method strings
When it happens
Trigger: new tls.TLSSocket(sock, { secureProtocol: 'TLSv1_2_method', minVersion: 'TLSv1.2' }); https.createServer({ secureProtocol: 'SSLv23_method', maxVersion: 'TLSv1.3' }); any options object carrying both knob styles.
Common situations: Migrating secureProtocol-era code and adding modern minVersion tuning without removing the legacy field; merging TLS options from multiple sources (base config + overrides); copy-pasted snippets that mix the two APIs.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- ERR_TLS_INVALID_PROTOCOL_METHOD
- ERR_TLS_INVALID_PROTOCOL_VERSION
- Unsupported 'alpnProtocols' option provided. 'h2' and 'http/
- Both 'cert' and 'key' must be provided to enable HTTPS
- ERR_INVALID_CHAR
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/0dd96aea98d01fbc.
Report an issue: GitHub.