perwendel/spark · error · IllegalArgumentException
Must provide a keystore file to run secured
Error message
Must provide a keystore file to run secured
What it means
Service.secure(...) switches the embedded server to HTTPS. A keystore file holding the server certificate/key is mandatory for TLS; without it Spark cannot build its SslStores. Spark throws IllegalArgumentException when keystoreFile is null, before any route mapping exception check would even apply.
Solutions
- Pass a valid, existing keystore file path as the first argument to secure(), e.g. secure("certs/keystore.jks", "password", null, null, null).
- Load the keystore path from config and fail early with a clear message if it is missing before calling secure().
- Verify the config/env providing the keystore location is actually loaded at startup.
Example fix
// before
String keystore = System.getProperty("keystore"); // null
Spark.secure(keystore, "pass", null, null);
// after
String keystore = Objects.requireNonNull(System.getProperty("keystore"), "keystore path required");
Spark.secure(keystore, "pass", null, null); Defensive patterns
Strategy: validation
Validate before calling
Objects.requireNonNull(keystoreFile, "Must provide a keystore file to run secured");
if (!java.nio.file.Files.exists(java.nio.file.Paths.get(keystoreFile))) {
throw new IllegalArgumentException("Keystore not found: " + keystoreFile);
}
Spark.secure(keystoreFile, password, null, null); Type guard
boolean isConfiguredSsl(String keystoreFile) { return keystoreFile != null && !keystoreFile.isEmpty(); } Try / catch
try {
Spark.secure(keystoreFile, password, null, null);
} catch (IllegalArgumentException e) {
LOG.error("SSL misconfiguration: {}", e.getMessage());
throw new IllegalStateException("Aborting startup: keystore missing", e);
} Prevention
- Fail fast at config-load time if the keystore path property is missing.
- Validate keystore file existence before calling secure().
- Keep SSL config in one well-tested bootstrap method.
When it happens
Trigger: Calling secure(null, ...) — i.e. passing a null keystore path — or a variable holding the keystore location that was never populated (config not loaded, property missing, env var empty).
Common situations: Keystore path read from application.properties/yml that is missing; conditional config where only truststore was set; forgetting the keystore argument when upgrading from an older secure() overload.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- HttpServletRequest cannot be null.
- This must be done after route mapping has begun
- WebSockets are only supported in the embedded server
- Server has not been properly initialized
- This must be done before route mapping has begun
AI-assisted analysis of perwendel/spark@1973e402f5 (2026-09-10).
Data as JSON: /api/errors/8b26c27becc180ee.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/spark/Service.java:293
* @param truststoreFile the truststore file location as string, leave null to reuse
* keystore
* @param needsClientCert Whether to require client certificate to be supplied in
* request
* @param truststorePassword the trust store password
* @return the object with connection set to be secure
*/
public synchronized Service secure(String keystoreFile,
String keystorePassword,
String certAlias,
String truststoreFile,
String truststorePassword,
boolean needsClientCert) {
if (initialized) {
throwBeforeRouteMappingException();
}
if (keystoreFile == null) {
throw new IllegalArgumentException(
"Must provide a keystore file to run secured");
}
sslStores = SslStores.create(keystoreFile, keystorePassword, certAlias, truststoreFile, truststorePassword, needsClientCert);
return this;
}
/**
* Configures the embedded web server's thread pool.
*
* @param maxThreads max nbr of threads.
* @return the object with the embedded web server's thread pool configured
*/
public synchronized Service threadPool(int maxThreads) {
return threadPool(maxThreads, -1, -1);
}
/**View on GitHub (pinned to 1973e402f5)