elastic/elasticsearch · error · SslConfigException
handshake timeout must be at least 1ms
Error message
handshake timeout must be at least 1ms
What it means
SslConfiguration rejects handshakeTimeoutMillis < 1 because a zero/negative timeout would either disable handshake enforcement or break the scheduler. The field is the upper bound the TLS engine waits for a peer handshake.
Source
Thrown at libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfiguration.java:91
SslClientAuthenticationMode clientAuth,
List<String> ciphers,
List<String> supportedProtocols,
long handshakeTimeoutMillis
) {
this.settingPrefix = settingPrefix;
this.explicitlyConfigured = explicitlyConfigured;
if (ciphers == null || ciphers.isEmpty()) {
throw new SslConfigException("cannot configure SSL/TLS without any supported cipher suites");
}
if (supportedProtocols == null || supportedProtocols.isEmpty()) {
throw new SslConfigException("cannot configure SSL/TLS without any supported protocols");
}
this.trustConfig = Objects.requireNonNull(trustConfig, "trust config cannot be null");
this.keyConfig = Objects.requireNonNull(keyConfig, "key config cannot be null");
this.verificationMode = Objects.requireNonNull(verificationMode, "verification mode cannot be null");
this.clientAuth = Objects.requireNonNull(clientAuth, "client authentication cannot be null");
if (handshakeTimeoutMillis < 1L) {
throw new SslConfigException("handshake timeout must be at least 1ms");
}
this.handshakeTimeoutMillis = handshakeTimeoutMillis;
this.ciphers = Collections.unmodifiableList(ciphers);
this.supportedProtocols = Collections.unmodifiableList(supportedProtocols);
}
public List<String> getCipherSuites() {
return ciphers;
}
/**
* @return A collection of files that are used by this SSL configuration. If the contents of these files change, then any
* subsequent call to {@link #createSslContext()} (or similar methods) may create a context with different behaviour.
* It is recommended that these files be monitored for changes, and a new ssl-context is created whenever any of the files are modified.
*/
public Collection<Path> getDependentFiles() {
Set<Path> paths = new HashSet<>(keyConfig.getDependentFiles());
paths.addAll(trustConfig.getDependentFiles());View on GitHub (pinned to db6a809a66)
Solutions
- Set ssl.handshake_timeout to a sensible positive duration (default is 10s), e.g. xpack.security.transport.ssl.handshake_timeout: 10s.
- If constructing programmatically, pass a value >= 1 (millis), e.g. Duration.ofSeconds(10).toMillis().
- Audit config templates for negative or zero time values across all ssl.* prefixes.
Example fix
// before xpack.security.transport.ssl.handshake_timeout: 0 // after xpack.security.transport.ssl.handshake_timeout: 10s
Defensive patterns
Strategy: validation
Validate before calling
long ensureHandshakeTimeout(org.elasticsearch.common.unit.TimeValue tv) {
long ms = tv.millis();
if (ms < 1L) throw new IllegalArgumentException("handshake_timeout must be >= 1ms, got " + tv);
return ms;
} Prevention
- Validate time-valued settings in your config layer before passing them to the loader.
- Treat 0/negative time values as config errors in templates.
- Lint ssl.*.handshake_timeout in CI.
When it happens
Trigger: Constructing SslConfiguration with handshakeTimeoutMillis <= 0. In the loader path this happens when ssl.handshake_timeout parses (via TimeValue.parseTimeValue) to 0ms or a negative duration (e.g. "-5s", "0ms").
Common situations: Operator sets xpack.security.transport.ssl.handshake_timeout: 0 thinking it disables the timeout; negative value from a templated config; units typo producing a sub-millisecond value rounded to 0.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- could not resolve ssl client authentication, unknown value [
- cannot configure SSL/TLS without any supported cipher suites
- cannot configure SSL/TLS without any supported protocols
- Setting prefix [{}] must be blank or end in '.'
- no protocols configured in [{}]
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/494eba95f4abf080.
Report an issue: GitHub.