NullPointerException in Java with no StackTrace
Asked Answered
C

12

452

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.

Chickpea answered 9/3, 2010 at 18:23 Comment(5)
What is the context? Are there multiple threads involved? I've had issues trying to get the stack trace of an exception in a SwingWorker.Sough
No threading involved here, just plain old Java.Chickpea
@Bozho - nope - not sure how to reproduce the NullPointer yet.Chickpea
related: #1076691Dithionite
More info on -XX:-OmitStackTraceInFastThrow in the dup: #4659651Quintet
K
578

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.

Kala answered 9/6, 2010 at 21:32 Comment(5)
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)?Chickpea
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.Kala
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: jawspeak.com/2010/05/26/…Opprobrious
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.Cowbird
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.Isodiametric
C
71

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?

Copula answered 9/3, 2010 at 18:50 Comment(4)
+1: This would explain the described behavior, and you are not the only one who discovered this :)Juggins
We actually have a standard policy of never using the first form above (LOG.error(exc);) - we always use the 2 parameter signature so that we add some descriptive statement to the logs instead of just a raw stacktrace.Chickpea
Sure, but policy doesn't mean it's always executed correctly! Figured it was worth mentioning, at least.Copula
True, but in this case it was ;-)Chickpea
P
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.

Permenter answered 9/3, 2010 at 23:26 Comment(4)
The bug is closed, but the -XX:-OmitStackTraceInFastThrow flag is still needed to workaround the performance optimization.Dithionite
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...Brooking
Pawel, have you tried the -XX:-OmitStackTraceInFastThrow JVM flag suggested by Joshua? See also https://mcmap.net/q/67682/-nullpointerexception-stack-trace-not-available-without-debug-agent.Permenter
This was it for us. Thanks.Carbazole
D
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...

Digamy answered 14/10, 2011 at 20:58 Comment(1)
Wayback machine link: web.archive.org/web/20190911113910/http://jawspeak.com/2010/05/…Vassily
J
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.

Juggins answered 9/3, 2010 at 18:25 Comment(5)
Sorry, I misspoke in my original post. I'm logging these through Log4J, which does use printStackTrace().Chickpea
Have you tried using getStackTrace() to make sure the problem is not with your logger?Juggins
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.Vase
@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?Compander
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.Compander
C
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.

Copula answered 9/3, 2010 at 20:14 Comment(0)
K
2

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()
Kirkwall answered 9/3, 2010 at 18:27 Comment(1)
See above - I misspoke - I am using printStackTrace().Chickpea
S
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

Sammysamoan answered 23/8, 2022 at 4:32 Comment(0)
C
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();
    }
Caption answered 9/3, 2010 at 18:31 Comment(0)
T
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.

Twentytwo answered 9/3, 2010 at 22:41 Comment(0)
K
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)
Kala answered 7/6, 2017 at 13:16 Comment(0)
F
0

I have solved this issue printing stackTrace inside for loop.

for (StackTraceElement st : e.getStackTrace()) {
   LOGGER.error(st.toString());
}

With this, it prints the whole stackTrace. Using other methods I can't obtain more info.

Fumarole answered 14/9, 2023 at 11:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.