434

I've had instances of our Java code catch a NullPointerException, but when I try to log the StackTrace (which basically ends up calling Throwable.printStackTrace() ), all I get is:

java.lang.NullPointerException

Has anyone else come across this? I tried googling for "java null pointer empty stack trace" but didn't come across anything like this.

Edward Shtern
  • 5,177
  • 5
  • 24
  • 24

11 Answers11

561

You are probably using the HotSpot JVM (originally by Sun Microsystems, later bought by Oracle, part of the OpenJDK), which performs a lot of optimization. To get the stack traces back, you need to pass the following option to the JVM:

-XX:-OmitStackTraceInFastThrow

The optimization is that when an exception (typically a NullPointerException) occurs for the first time, the full stack trace is printed and the JVM remembers the stack trace (or maybe just the location of the code). When that exception occurs often enough, the stack trace is not printed anymore, both to achieve better performance and not to flood the log with identical stack traces.

To see how this is implemented in the HotSpot JVM, grab a copy of it and search for the global variable OmitStackTraceInFastThrow. Last time I looked at the code (in 2019), it was in the file graphKit.cpp.

Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
Roland Illig
  • 40,703
  • 10
  • 88
  • 121
  • 1
    Thanks for the tip. Any idea if there are any hidden gotchas to passing this option (it seems pretty innocuous as long as my application doesn't throw a ton of exceptions)? – Edward Shtern Jun 11 '10 at 17:48
  • There are no hidden gotchas that I know of. When you look at the Hotspot source code, you can see that this option is only used in one place (graphKit.cpp). And that looks fine to me. – Roland Illig Jun 13 '10 at 11:14
  • 37
    Thought I'd add the additional bit of information that when the stack trace gets optimized away, it's because it has gotten fully handled at least once: http://jawspeak.com/2010/05/26/hotspot-caused-exceptions-to-lose-their-stack-traces-in-production-and-the-fix/ – sharakan Jun 19 '12 at 14:56
  • 1
    I am running an OpenJDK JVM, version 1.8.0u171 (Debian 9), and it seems to accept the `-XX:-OmitStackTraceInFastThrow` flag as well. I've yet to confirm if that was why I was also failing to print stack-traces (e.g., using `e.printStackTrace`), but it seems highly likely. I've expanded the answer to reflect this discovery. – Chris W. Jun 05 '18 at 17:12
  • In our case first 125 exceptions had a stack trace, and then the rest across 3 rotations of log files had none. This answer was very helpful in finding the culprit. – sukhmel May 27 '20 at 10:03
69

As you mentioned in a comment, you're using log4j. I discovered (inadvertently) a place where I had written

LOG.error(exc);

instead of the typical

LOG.error("Some informative message", e);

through laziness or perhaps just not thinking about it. The unfortunate part of this is that it doesn't behave as you expect. The logger API actually takes Object as the first argument, not a string - and then it calls toString() on the argument. So instead of getting the nice pretty stack trace, it just prints out the toString - which in the case of NPE is pretty useless.

Perhaps this is what you're experiencing?

Steven Schlansker
  • 37,580
  • 14
  • 81
  • 100
36

We have seen this same behavior in the past. It turned out that, for some crazy reason, if a NullPointerException occurred at the same place in the code multiple times, after a while using Log.error(String, Throwable) would stop including full stack traces.

Try looking further back in your log. You may find the culprit.

EDIT: this bug sounds relevant, but it was fixed so long ago it's probably not the cause.

Matt Solnit
  • 32,152
  • 8
  • 53
  • 57
  • 3
    The bug is closed, but the -XX:-OmitStackTraceInFastThrow flag is still needed to workaround the performance optimization. – Joshua Goldberg Jan 30 '12 at 22:09
  • I've been seeing this recently a lot. Any clues as to what might be causing this, or how to fix it? The logging system may have been up for days, and the actual cause rotated out, nevermind the tedious search... – Pawel Veselov Dec 14 '12 at 08:57
  • 5
    Pawel, have you tried the `-XX:-OmitStackTraceInFastThrow` JVM flag suggested by Joshua? See also http://stackoverflow.com/a/2070568/6198. – Matt Solnit Dec 14 '12 at 23:38
  • 1
    This was it for us. Thanks. – Andrew Cheong Nov 18 '19 at 19:24
24

Here is an explanation : Hotspot caused exceptions to lose their stack traces in production – and the fix

I've tested it on Mac OS X

  • java version "1.6.0_26"
  • Java(TM) SE Runtime Environment (build 1.6.0_26-b03-383-11A511)
  • Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02-383, mixed mode)

    Object string = "abcd";
    int i = 0;
    while (i < 12289) {
        i++;
        try {
            Integer a = (Integer) string;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

For this specific fragment of code, 12288 iterations (+frequency?) seems to be the limit where JVM has decided to use preallocated exception...

Benoît Guérout
  • 1,977
  • 3
  • 21
  • 30
  • 3
    Wayback machine link: https://web.archive.org/web/20190911113910/http://jawspeak.com/2010/05/26/hotspot-caused-exceptions-to-lose-their-stack-traces-in-production-and-the-fix/ – aff Apr 19 '22 at 11:46
11

exception.toString does not give you the StackTrace, it only returns

a short description of this throwable. The result is the concatenation of:

* the name of the class of this object
* ": " (a colon and a space)
* the result of invoking this object's getLocalizedMessage() method

Use exception.printStackTrace instead to output the StackTrace.

Peter Lang
  • 54,264
  • 27
  • 148
  • 161
  • 1
    Sorry, I misspoke in my original post. I'm logging these through Log4J, which does use printStackTrace(). – Edward Shtern Mar 09 '10 at 18:34
  • 1
    Have you tried using `getStackTrace()` to make sure the problem is not with your logger? – Peter Lang Mar 09 '10 at 18:37
  • 1
    If you are using log4j, be sure to send the exception as part of the argument to the log method. I will post an answer with that. – Ravi Wallau Mar 09 '10 at 18:53
  • @raviaw valid point! @Edward Shtern: can you confirm that you definitely are using the 2-arg form of the log4j method? I know you mentioned in an answer further down that it is the company policy to do so, but are you ABSOLUTELY sure that in this case you are following the policy? – KarstenF Mar 09 '10 at 23:44
  • It might be a long shot, but is it possible that the exception originates in some 3rd party code? Maybe it is a (poorly written) exception wrapper, whose toString() simply returns the class name of the wrapped exception, and which fails to provide the underlying stack trace. Try put something like logger.info("Exception class = " + exc.class.getCanonicalName()) into your catch block and see what you get. – KarstenF Mar 10 '10 at 19:16
5

Alternate suggestion - if you're using Eclipse, you could set a breakpoint on NullPointerException itself (in the Debug perspective, go to the "Breakpoints" tab and click on the little icon that has a ! in it)

Check both the "caught" and "uncaught" options - now when you trigger the NPE, you'll immediately breakpoint and you can then step through and see how exactly it is handled and why you're not getting a stack trace.

Steven Schlansker
  • 37,580
  • 14
  • 81
  • 100
2

VM stops outputting the stack trace of the exceptions which have been thrown a few times. This is a one of optimizations which happens in C2 compile.

According to the source code of OpenJDK, this optimization is applied to following exceptions:

-NullPointerException -ArithmeticException -ArrayIndexOutOfBoundsException -ArrayStoreException -ClassCastException

S4RUUL
  • 141
  • 1
  • 3
1

toString() only returns the exception name and the optional message. I would suggest calling

exception.printStackTrace()

to dump the message, or if you need the gory details:

 StackTraceElement[] trace = exception.getStackTrace()
1

This will output the Exception, use only to debug you should handle you exceptions better.

import java.io.PrintWriter;
import java.io.StringWriter;
    public static String getStackTrace(Throwable t)
    {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw, true);
        t.printStackTrace(pw);
        pw.flush();
        sw.flush();
        return sw.toString();
    }
Michael D. Irizarry
  • 6,186
  • 5
  • 30
  • 35
1

(Your question is still unclear on whether your code is calling printStackTrace() or this is being done by a logging handler.)

Here are some possible explanations about what might be happening:

  • The logger / handler being used has been configured to only output the exception's message string, not a full stack trace.

  • Your application (or some third-party library) is logging the exception using LOG.error(ex); rather than the 2-argument form of (for example) the log4j Logger method.

  • The message is coming from somewhere different to where you think it is; e.g. it is actually coming some third-party library method, or some random stuff left over from earlier attempts to debug.

  • The exception that is being logged has overloaded some methods to obscure the stacktrace. If that is the case, the exception won't be a genuine NullPointerException, but will be some custom subtype of NPE or even some unconnected exception.

I think that the last possible explanation is pretty unlikely, but people do at least contemplate doing this kind of thing to "prevent" reverse engineering. Of course it only really succeeds in making life difficult for honest developers.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
1

When you are using AspectJ in your project, it may happen that some aspect hides its portion of the stack trace. For example, today I had:

java.lang.NullPointerException:
  at com.company.product.MyTest.test(MyTest.java:37)

This stack trace was printed when running the test via Maven's surefire.

On the other hand, when running the test in IntelliJ, a different stack trace was printed:

java.lang.NullPointerException
  at com.company.product.library.ArgumentChecker.nonNull(ArgumentChecker.java:67)
  at ...
  at com.company.product.aspects.CheckArgumentsAspect.wrap(CheckArgumentsAspect.java:82)
  at ...
  at com.company.product.MyTest.test(MyTest.java:37)
Roland Illig
  • 417
  • 1
  • 5
  • 15