apache / apache/logging-log4j2
ThrowableStackTraceRenderer throws NullPointerException when Throwable.getCause() returns different instances
- Dominant language
- Java
- Stars
- 3.6k
- Forks
- 1.7k
- Avg merge
- 21h 30m
- Merged PRs (30d)
- 27
Description
## Description
Our exception overrides getCause() and returns a new Throwable instance on each invocation. While this implementation is unconventional, Log4j 2.24.3 logs the exception successfully, whereas 2.25.3 throws an internal NullPointerException from ThrowableStackTraceRenderer.
## Configuration
**Version:** 2.25.3, 2.26.0, 2.26.1
**Operating system:** Windows 11 Enterprise
**JDK:** Java 25
## Logs
```
2026-09-01T13:25:19.053233100Z main ERROR An exception occurred processing Appender CONSOLE
java.lang.NullPointerException: Cannot read field "stackLength" because "metadata" is null
at org.apache.logging.log4j.core.pattern.ThrowableStackTraceRenderer.renderStackTraceElements(ThrowableStackTraceRenderer.java:158)
at org.apache.logging.log4j.core.pattern.ThrowableStackTraceRenderer.renderThrowable(ThrowableStackTraceRenderer.java:100)
at org.apache.logging.log4j.core.pattern.ThrowableStackTraceRenderer.renderCause(ThrowableStackTraceRenderer.java:136)
at org.apache.logging.log4j.core.pattern.ThrowableStackTraceRenderer.renderThrowable(ThrowableStackTraceRenderer.java:103)
at org.apache.logging.log4j.core.pattern.ThrowableStackTraceRenderer.renderThrowable(ThrowableStackTraceRenderer.java:77)
at org.apache.logging.log4j.core.pattern.ThrowableStackTraceRenderer.renderThrowable(ThrowableStackTraceRenderer.java:56)
at org.apache.logging.log4j.core.pattern.ThrowablePatternConverter.format(ThrowablePatternConverter.java:130)
at org.apache.logging.log4j.core.layout.PatternLayout$NoFormatPatternSerializer.toSerializable(PatternLayout.java:354)
at org.apache.logging.log4j.core.layout.PatternLayout.toText(PatternLayout.java:251)
at org.apache.logging.log4j.core.layout.PatternLayout.encode(PatternLayout.java:237)
at org.apache.logging.log4j.core.layout.PatternLayout.encode(PatternLayout.java:57)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.directEncodeEvent(AbstractOutputStreamAppender.java:227)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.tryAppend(AbstractOutputStreamAppender.java:220)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:211)
at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:160)
at org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:133)
at org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:124)
at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:88)
at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:711)
at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:669)
at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:645)
at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:589)
at org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy.log(AwaitCompletionReliabilityStrategy.java:92)
at org.apache.logging.log4j.core.Logger.log(Logger.java:187)
at org.apache.logging.log4j.spi.AbstractLogger.tryLogMessage(AbstractLogger.java:2970)
at org.apache.logging.log4j.spi.AbstractLogger.logMessageTrackRecursion(AbstractLogger.java:2922)
at org.apache.logging.log4j.spi.AbstractLogger.logMessageSafely(AbstractLogger.java:2904)
at org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:2648)
at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:2587)
at org.apache.logging.log4j.spi.AbstractLogger.error(AbstractLogger.java:824)
at Log4jBugTest.test(Log4jBugTest.java:26)
```
## Reproduction
```
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;
class Log4jBugTest
{
private static final Logger LOGGER = LogManager.getLogger(Log4jBugTest.class);
@Test
void test()
{
try
{
throw new Exception("Exception")
{
@Override
public synchronized Throwable getCause()
{
return new Throwable("Throwable");
}
};
}
catch (final Exception e)
{
LOGGER.error("Error", e);
}
}
}
```
And my log4j2 config:
```
```
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with ThrowableStackTraceRenderer.java at the failing renderStackTraceElements path and reproduce the issue using the supplied Log4jBugTest.java example with the shown %ex configuration. Trace how the changing getCause() result leads to missing metadata; done means logging the exception no longer throws an internal NullPointerException and the regression is covered by a test.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- observability-sre
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100