In the log, we get an exception and stacktrace like the following (somewhat
elided):
org.springframework.context.ApplicationContextException: Unable to start web
server
at
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:170)
at
org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:619)
at
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
at
org.springframework.boot.SpringApplication.refresh(SpringApplication.java:755)
Caused by: org.springframework.boot.web.server.WebServerException: Unable to
start embedded Tomcat
at
org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:147)
at
org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:107)
... 8 common frames omitted
Caused by: java.lang.IllegalStateException:
StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[/msapi]
failed to start
at
org.springframework.boot.web.embedded.tomcat.TomcatWebServer.rethrowDeferredStartupExceptions(TomcatWebServer.java:209)
at
org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:131)
... 13 common frames omitted
No other relevant information is provided either before this or after this.
If I’m able to repeat this test case on the desktop, I can set breakpoints in
“StandardContext”, like on this line:
getLogger().error(sm.getString("standardContext.filterStart", name), throwable);
when I inspect the throwable, I can clearly see what the actual root cause is
(what it is is moot for this discussion), but this logger line doesn’t print
anything, not in the console certainly.
When we can’t repeat the test case on the desktop, I’ve been having people
decompile this class and add manual “ex.printStackTrace()” calls in these catch
clauses, but that is obviously not ideal.
I’ve been struggling with this problem for months now with no real solution. I
do find that some other log statements in this class that simply reference the
“log” instance variable can be enabled with “logger.level” property settings,
but I’ve found nothing that enables what I actually need to see.
From: Piotr P. Karwasz <[email protected]>
Sent: Monday, November 10, 2025 11:02 AM
To: [email protected]
Subject: Re: Still struggling with getting root causes of exceptions in
tomcat-embed-core in SpringBoot applications
Hi David, On 6. 11. 2025 19: 51, KARR, DAVID wrote: > We support a large number
of SpringBoot applications using tomcat- > embed-core (currently at 10. 1. 41).
There are some configuration issues > that result in the service startup failing
Hi David,
On 6.11.2025 19:51, KARR, DAVID wrote:
> We support a large number of SpringBoot applications using tomcat-
> embed-core (currently at 10.1.41). There are some configuration issues
> that result in the service startup failing with a "Tomcat startup"
> exception, which provides no information about the actual root cause.
Could you clarify what you mean by “root cause”?
Do you see no stack trace at all in the logs, or do you see a stack
trace that doesn’t include the original exception cause?
> I also note that in the service that shows the root cause, I see this in my
> log:
>
> 08:43:14,376 |-INFO in
> ch.qos.logback.classic.jul.LevelChangePropagator@4eba373c<mailto:ch.qos.logback.classic.jul.LevelChangePropagator@4eba373c>
> - Propagating DEBUG level on Logger[org.apache.catalina] onto the JUL
> framework
>
> I do NOT see that in the service that is not showing the root cause.
This message appears when Spring Boot installs SLF4JBridgeHandler [1] as
the `java.util.logging` (JUL) handler for all log events.
It’s worth noting that:
- The bridge is not installed at JVM startup, but later during Spring
Boot initialization (specifically, when the `Environment` becomes
available), so some early JUL events may not be captured.
- The installation is conditional: if JUL has exactly one
`ConsoleHandler`, Spring Boot replaces it with the bridge.
Therefore, behavior depends on the active `logging.properties` file.
- Before the bridge is active, JUL log levels and handlers are still
governed by `logging.properties`, which may differ from Logback’s
configuration or Spring Boot’s backend-independent `logging.level.*`
[2] settings.
These factors can explain why you’re missing some log output during startup.
To make Tomcat’s logging more consistent and deterministic, you could
consider one or both of the following approaches:
### 1. Use an alternative Tomcat JULI backend
By default, Tomcat JULI uses the standard JUL backend, which is not very
friendly to replace. Spring Boot mitigates this by redirecting JUL
output as soon as possible, but there’s still a window where messages
can be lost.
Fortunately, you can replace Tomcat’s JULI backend entirely by adding a
different implementation to the classpath. Two good options are:
- Direct “Tomcat JULI → SLF4J” bridge [3]
- Indirect “Tomcat JULI → Log4j API” bridge [4] (maintained by ASF
Logging Services)
Either works out of the box, since Spring Boot already includes the
”Log4j API → SLF4J” bridge (`log4j-to-slf4j` [5]).
With these bridges, all Tomcat log events will flow through Logback from
the very beginning of the JVM lifecycle.
### 2. Use an alternative JUL implementation
There are two ways to “replace” JUL itself:
- Use the standard `java.util.logging.LogManager` but forward its
messages to another backend.
This is what Spring Boot currently does, though it can cause double
filtering: once in JUL and again in the target backend. If
configurations are not aligned, some messages may be dropped. Aligning
the configuration is the job of the LevelChangePropagator.
- Use an alternative `LogManager` implementation such as
`org.apache.logging.log4j.jul.LogManager` [6], which forwards all JUL
calls directly to the Log4j API.
Replacing JUL completely is tricky: it must be done via the launcher
script or a static initializer in your main class.
Since JDK-8262741 [7] (which would allow ServiceLoader-based
replacement) is unlikely to be implemented, we are considering writing
a lightweight, Log4j-agnostic replacement `LogManager`. However,
that’s currently low on our priority list.
Best regards,
Piotr
References:
[1]
https://urldefense.com/v3/__https://www.slf4j.org/api/org/slf4j/bridge/SLF4JBridgeHandler.html__;!!BhdT!h63Vyc5jU6mEPmRuDa-JW8MG_hYZKroKdhPYxqtSzy1Zv0s-9itKvrb69dA6Bj3LT9_oxgUfZ8rhSCOUDKAa_w$<https://urldefense.com/v3/__https:/www.slf4j.org/api/org/slf4j/bridge/SLF4JBridgeHandler.html__;!!BhdT!h63Vyc5jU6mEPmRuDa-JW8MG_hYZKroKdhPYxqtSzy1Zv0s-9itKvrb69dA6Bj3LT9_oxgUfZ8rhSCOUDKAa_w$>
[2]
https://urldefense.com/v3/__https://docs.spring.io/spring-boot/appendix/application-properties/index.html*application-properties.core.logging.level__;Iw!!BhdT!h63Vyc5jU6mEPmRuDa-JW8MG_hYZKroKdhPYxqtSzy1Zv0s-9itKvrb69dA6Bj3LT9_oxgUfZ8rhSCNPXjexLQ$<https://urldefense.com/v3/__https:/docs.spring.io/spring-boot/appendix/application-properties/index.html*application-properties.core.logging.level__;Iw!!BhdT!h63Vyc5jU6mEPmRuDa-JW8MG_hYZKroKdhPYxqtSzy1Zv0s-9itKvrb69dA6Bj3LT9_oxgUfZ8rhSCNPXjexLQ$>
[3]
https://urldefense.com/v3/__https://github.com/tomcat-slf4j-logback/tomcat-slf4j-logback__;!!BhdT!h63Vyc5jU6mEPmRuDa-JW8MG_hYZKroKdhPYxqtSzy1Zv0s-9itKvrb69dA6Bj3LT9_oxgUfZ8rhSCOkKEDETQ$<https://urldefense.com/v3/__https:/github.com/tomcat-slf4j-logback/tomcat-slf4j-logback__;!!BhdT!h63Vyc5jU6mEPmRuDa-JW8MG_hYZKroKdhPYxqtSzy1Zv0s-9itKvrb69dA6Bj3LT9_oxgUfZ8rhSCOkKEDETQ$>
[4]
https://urldefense.com/v3/__https://logging.apache.org/log4j/2.x/jakarta.html*replace-tomcat__;Iw!!BhdT!h63Vyc5jU6mEPmRuDa-JW8MG_hYZKroKdhPYxqtSzy1Zv0s-9itKvrb69dA6Bj3LT9_oxgUfZ8rhSCP7B1lo2g$<https://urldefense.com/v3/__https:/logging.apache.org/log4j/2.x/jakarta.html*replace-tomcat__;Iw!!BhdT!h63Vyc5jU6mEPmRuDa-JW8MG_hYZKroKdhPYxqtSzy1Zv0s-9itKvrb69dA6Bj3LT9_oxgUfZ8rhSCP7B1lo2g$>
[5]
https://urldefense.com/v3/__https://logging.apache.org/log4j/2.x/components.html*log4j-to-slf4j__;Iw!!BhdT!h63Vyc5jU6mEPmRuDa-JW8MG_hYZKroKdhPYxqtSzy1Zv0s-9itKvrb69dA6Bj3LT9_oxgUfZ8rhSCNCruw2Vg$<https://urldefense.com/v3/__https:/logging.apache.org/log4j/2.x/components.html*log4j-to-slf4j__;Iw!!BhdT!h63Vyc5jU6mEPmRuDa-JW8MG_hYZKroKdhPYxqtSzy1Zv0s-9itKvrb69dA6Bj3LT9_oxgUfZ8rhSCNCruw2Vg$>
[6]
https://urldefense.com/v3/__https://logging.apache.org/log4j/2.x/log4j-jul.html*bridge-logmanager__;Iw!!BhdT!h63Vyc5jU6mEPmRuDa-JW8MG_hYZKroKdhPYxqtSzy1Zv0s-9itKvrb69dA6Bj3LT9_oxgUfZ8rhSCNf51eamQ$<https://urldefense.com/v3/__https:/logging.apache.org/log4j/2.x/log4j-jul.html*bridge-logmanager__;Iw!!BhdT!h63Vyc5jU6mEPmRuDa-JW8MG_hYZKroKdhPYxqtSzy1Zv0s-9itKvrb69dA6Bj3LT9_oxgUfZ8rhSCNf51eamQ$>
[7]
https://urldefense.com/v3/__https://bugs.openjdk.org/browse/JDK-8262741__;!!BhdT!h63Vyc5jU6mEPmRuDa-JW8MG_hYZKroKdhPYxqtSzy1Zv0s-9itKvrb69dA6Bj3LT9_oxgUfZ8rhSCNPalYWxw$<https://urldefense.com/v3/__https:/bugs.openjdk.org/browse/JDK-8262741__;!!BhdT!h63Vyc5jU6mEPmRuDa-JW8MG_hYZKroKdhPYxqtSzy1Zv0s-9itKvrb69dA6Bj3LT9_oxgUfZ8rhSCNPalYWxw$>
---------------------------------------------------------------------
To unsubscribe, e-mail:
[email protected]<mailto:[email protected]>
For additional commands, e-mail:
[email protected]<mailto:[email protected]>