Skip to content

Catch LinkageError in ThrowableExtendedStackTraceRenderer#loadClass (#4028)#4049

Open
chanani wants to merge 2 commits intoapache:2.xfrom
chanani:fix/4028
Open

Catch LinkageError in ThrowableExtendedStackTraceRenderer#loadClass (#4028)#4049
chanani wants to merge 2 commits intoapache:2.xfrom
chanani:fix/4028

Conversation

@chanani
Copy link

@chanani chanani commented Feb 19, 2026

Summary

The loadClass method in ThrowableExtendedStackTraceRenderer only catches Exception,
but ClassLoader can throw NoClassDefFoundError, which extends LinkageError (an Error
subclass). This causes the entire log event to fail with AppenderLoggingException instead
of gracefully degrading when a class in the stack trace cannot be resolved.

Changes

  • ThrowableExtendedStackTraceRenderer.java: Changed catch (Exception) to
    catch (Exception | LinkageError) in the loadClass method
  • ThrowableExtendedStackTraceRendererTest.java: Added two test cases:
    • Verifies rendering succeeds when a stack trace references a non-existent class
    • Verifies rendering succeeds when a custom ClassLoader throws NoClassDefFoundError
  • Changelog entry: Added 4028_fix_catch_LinkageError_in_ThrowableExtendedStackTraceRenderer.xml

Root Cause

// Before: Only catches Exception — NoClassDefFoundError (Error) escapes
catch (final Exception ignored)

// After: Also catches LinkageError, which is the parent of NoClassDefFoundError
catch (final Exception | LinkageError ignored)

Java's Throwable hierarchy:

Throwable
├── Exception        ← previously caught
└── Error
       └── LinkageError ← now also caught
                  └── NoClassDefFoundError

Fixes #4028

…s` (apache#4028)

Signed-off-by: CHANHAN <130114269+chanani@users.noreply.github.com>
@chanani
Copy link
Author

chanani commented Feb 19, 2026

Hi @vy, thanks for the encouragement!

Here's what this PR includes:

  • Fix: Changed catch (Exception) to catch (Exception | LinkageError) in ThrowableExtendedStackTraceRenderer#loadClass
  • Tests: Two test cases covering NoClassDefFoundError scenarios
  • Changelog: Added entry for this fix

Let me know if any changes are needed!

Copy link
Member

@vy vy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chanani, thanks so much for the (AI-generated?) fix. Please make sure ./mvnw -pl :log4j-core install && ./mvnw -pl :log4j-core-test verify succeeds when wrapping up your changes.

https://logging.apache.org/xml/ns/log4j-changelog-0.xsd"
type="fixed">
<issue id="4028" link="https://github.com/apache/logging-log4j2/issues/4028"/>
<description format="asciidoc">Catch `LinkageError` in `ThrowableExtendedStackTraceRenderer#loadClass` to prevent `NoClassDefFoundError` from breaking logging</description>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<description format="asciidoc">Catch `LinkageError` in `ThrowableExtendedStackTraceRenderer#loadClass` to prevent `NoClassDefFoundError` from breaking logging</description>
<description format="asciidoc">Ensure all `Throwable`s are handled while rendering stack traces</description>

xsi:schemaLocation="https://logging.apache.org/xml/ns
https://logging.apache.org/xml/ns/log4j-changelog-0.xsd"
type="fixed">
<issue id="4028" link="https://github.com/apache/logging-log4j2/issues/4028"/>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<issue id="4028" link="https://github.com/apache/logging-log4j2/issues/4028"/>
<issue id="4049" link="https://github.com/apache/logging-log4j2/pull/4049"/>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding a new test file, would you mind extending ThrowablePatternConverterTest.StackTraceTest, please?

return clazz;
}
} catch (final Exception ignored) {
} catch (final Exception | LinkageError ignored) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
} catch (final Exception | LinkageError ignored) {
} catch (final Throwable ignored) {

@github-project-automation github-project-automation bot moved this to Changes requested in Log4j pull request tracker Feb 28, 2026
…che#4028)

- Changed catch (Exception) to catch (Throwable) in loadClass method
- Moved tests into ThrowablePatternConverterTest.StackTraceTest
- Removed standalone ThrowableExtendedStackTraceRendererTest
- Updated changelog description and issue link per review feedback

Signed-off-by: CHANHAN <130114269+chanani@users.noreply.github.com>
@chanani
Copy link
Author

chanani commented Mar 1, 2026

Hi @vy, thank you for the review! I've addressed all the feedback.

  1. catch (Throwable) — Applied the suggested change to catch all Throwables instead of Exception | LinkageError
  2. Changelog description — Updated to "Ensure all Throwables are handled while rendering stack traces"
  3. Changelog issue link — Changed from #4028 to #4049
  4. Tests moved — Removed ThrowableExtendedStackTraceRendererTest and added the test cases into ThrowablePatternConverterTest.StackTraceTest as requested

Please let me know if any further changes are needed!

@vy
Copy link
Member

vy commented Mar 2, 2026

@chanani, TestFriendlyException is already containing a stack trace element of a non-existent class: ORG_APACHE_REPLACEMENT_STACK_TRACE_ELEMENT. Any ideas on why does this NoClassDefFoundError not surface with the existing test suite?

@chanani
Copy link
Author

chanani commented Mar 3, 2026

Hi @vy,

The reason NoClassDefFoundError doesn't surface with the existing test suite is the difference between two exception paths:

  1. ClassNotFoundException (extends Exception) — Thrown by ClassLoader.loadClass() when a class simply doesn't exist on the classpath. That's the case for bar.OrgApacheReplacement — it was never on the classpath, so the class loader search fails cleanly with ClassNotFoundException, which was already caught by the previous catch (Exception)

  2. NoClassDefFoundError (extends LinkageErrorError) — Thrown when the class is found but fails during linking/initialization (e.g., a missing dependency at link time). This is the scenario from issue ThrowableExtendedStackTraceRenderer catches Exception but not Error #4028, and it wasn't caught by catch (Exception)

So the existing test with ORG_APACHE_REPLACEMENT_STACK_TRACE_ELEMENT exercises the ClassNotFoundException path, not the NoClassDefFoundError path

Please let me know if any further changes are needed !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Changes requested

Development

Successfully merging this pull request may close these issues.

ThrowableExtendedStackTraceRenderer catches Exception but not Error

2 participants