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]>


Reply via email to