{"record":{"id":"494eba95f4abf080","repo":"elastic/elasticsearch","slug":"handshake-timeout-must-be-at-least-1ms","errorCode":null,"errorMessage":"handshake timeout must be at least 1ms","messagePattern":"handshake timeout must be at least 1ms","errorType":"exception","errorClass":"SslConfigException","httpStatus":null,"severity":"error","filePath":"libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfiguration.java","lineNumber":91,"sourceCode":"        SslClientAuthenticationMode clientAuth,\n        List<String> ciphers,\n        List<String> supportedProtocols,\n        long handshakeTimeoutMillis\n    ) {\n        this.settingPrefix = settingPrefix;\n        this.explicitlyConfigured = explicitlyConfigured;\n        if (ciphers == null || ciphers.isEmpty()) {\n            throw new SslConfigException(\"cannot configure SSL/TLS without any supported cipher suites\");\n        }\n        if (supportedProtocols == null || supportedProtocols.isEmpty()) {\n            throw new SslConfigException(\"cannot configure SSL/TLS without any supported protocols\");\n        }\n        this.trustConfig = Objects.requireNonNull(trustConfig, \"trust config cannot be null\");\n        this.keyConfig = Objects.requireNonNull(keyConfig, \"key config cannot be null\");\n        this.verificationMode = Objects.requireNonNull(verificationMode, \"verification mode cannot be null\");\n        this.clientAuth = Objects.requireNonNull(clientAuth, \"client authentication cannot be null\");\n        if (handshakeTimeoutMillis < 1L) {\n            throw new SslConfigException(\"handshake timeout must be at least 1ms\");\n        }\n        this.handshakeTimeoutMillis = handshakeTimeoutMillis;\n        this.ciphers = Collections.unmodifiableList(ciphers);\n        this.supportedProtocols = Collections.unmodifiableList(supportedProtocols);\n    }\n\n    public List<String> getCipherSuites() {\n        return ciphers;\n    }\n\n    /**\n     * @return A collection of files that are used by this SSL configuration. If the contents of these files change, then any\n     * subsequent call to {@link #createSslContext()} (or similar methods) may create a context with different behaviour.\n     * It is recommended that these files be monitored for changes, and a new ssl-context is created whenever any of the files are modified.\n     */\n    public Collection<Path> getDependentFiles() {\n        Set<Path> paths = new HashSet<>(keyConfig.getDependentFiles());\n        paths.addAll(trustConfig.getDependentFiles());","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfiguration.java#L73-L109","documentation":"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.","triggerScenarios":"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\").","commonSituations":"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.","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."],"exampleFix":"// before\nxpack.security.transport.ssl.handshake_timeout: 0\n// after\nxpack.security.transport.ssl.handshake_timeout: 10s","handlingStrategy":"validation","validationCode":"long ensureHandshakeTimeout(org.elasticsearch.common.unit.TimeValue tv) {\n    long ms = tv.millis();\n    if (ms < 1L) throw new IllegalArgumentException(\"handshake_timeout must be >= 1ms, got \" + tv);\n    return ms;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["ssl","config","timeout","validation"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}