perwendel/spark · error · IllegalStateException
This must be done after route mapping has begun
Error message
This must be done after route mapping has begun
What it means
Service.port() returns the port the embedded Spark server is actually listening on. That value only exists once route mapping has begun and the server configuration has been initialized; before that the port field is meaningless. Spark therefore throws IllegalStateException if port() is called too early, as documented by its @throws clause.
Solutions
- Move the port() call after route mapping has begun (after at least one get/post/put/etc. or staticFiles call), ideally after init() and awaitInitialization().
- If you need the port before mapping, set it explicitly with port(4567) and use your own constant instead of reading it back.
- Use awaitInitialization() first, then call port() to ensure the server is fully started.
Example fix
// before
Spark.get("/hello", (req, res) -> "hi");
int p = Spark.port(); // may throw if called before mapping
// after
Spark.get("/hello", (req, res) -> "hi");
Spark.awaitInitialization();
int p = Spark.port(); // safe Defensive patterns
Strategy: try-catch
Validate before calling
if (sparkService != null && isRouteMappingStarted()) {
int p = sparkService.port();
} Type guard
boolean portReadable(spark.Service s) { return s != null && isRouteMappingStarted(); } // no public initialized check; track mapping start yourself Try / catch
try {
int p = Spark.port();
} catch (IllegalStateException e) {
// called before route mapping; use configured default instead
int p = DEFAULT_PORT;
} Prevention
- Call port() only after awaitInitialization().
- Track whether you've mapped routes before querying server state.
- Store the port you set with port(int) in your own constant for early access.
When it happens
Trigger: Calling port() on the Service instance (or the static Spark.port()) before any route mapping call (get/post/staticFiles etc.) has triggered initialization — e.g. calling it immediately at the top of main() before mapping routes.
Common situations: Logging 'running on port X' before routes are mapped; reading the port in a constructor or static initializer; frameworks/integration code that query the port at startup before defining routes.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Server has not been properly initialized
- This must be done before route mapping has begun
- HttpServletRequest cannot be null.
- Must provide a keystore file to run secured
- WebSockets are only supported in the embedded server
AI-assisted analysis of perwendel/spark@1973e402f5 (2026-09-10).
Data as JSON: /api/errors/afe175eba82c3311.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/spark/Service.java:185
public synchronized Service port(int port) {
if (initialized) {
throwBeforeRouteMappingException();
}
this.port = port;
return this;
}
/**
* Retrieves the port that Spark is listening on.
*
* @return The port Spark server is listening on.
* @throws IllegalStateException when the server is not started
*/
public synchronized int port() {
if (initialized) {
return port;
} else {
throw new IllegalStateException("This must be done after route mapping has begun");
}
}
/**
* Set the connection to be secure, using the specified keystore and
* truststore. This has to be called before any route mapping is done. You
* have to supply a keystore file, truststore file is optional (keystore
* will be reused). By default, client certificates are not checked.
* This method is only relevant when using embedded Jetty servers. It should
* not be used if you are using Servlets, where you will need to secure the
* connection in the servlet container
*
* @param keystoreFile The keystore file location as string
* @param keystorePassword the password for the keystore
* @param truststoreFile the truststore file location as string, leave null to reuse
* keystore
* @param truststorePassword the trust store password
* @return the object with connection set to be secureView on GitHub (pinned to 1973e402f5)