apache / apache/logging-log4j2

ThrowableStackTraceRenderer throws NullPointerException when Throwable.getCause() returns different instances

Open
#4,279 0 comments 0 reactions 0 assignees View on GitHub
waiting-for-maintainer
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.