Hacker News new | past | comments | ask | show | jobs | submit login

I really like your last point "whatever the computer is telling is true from the computer point of view".

In a surprising number of coding interviews that I've conducted, I've seen a candidate write an incorrect solution that generates an exception and then attempt to figure out the error almost on first principles, rather than actually reading the exception carefully and thinking about what coding errors could have caused it to happen. The exception message is a _huge_ hint!

It's a red flag to see someone try to debug without paying attention to it. Conversely it's very positive to see someone encounter one and then think carefully about it. Writing an incorrect solution but then testing it out and showing the ability to debug and fix it systematically and expediently is no worse than getting it right on the first try, in my book.




It isn't just a huge hint, most of the time it tells you exactly what the damn issue is. This discussion is blowing my mind.

I am honestly speechless. IT GIVES YOU THE LINE NUMBER AND THE FUNCTION CALL AND THE REASON! Why would you ever even attempt to debug without parsing it?


Wait wait wait.

Not so fast.

i'm one of those programmers who read manuals and stack traces but I have to admit that I've seen my share of both manuals as well as stack traces that didn't make much sense.


This is my experience with Clojure stack traces ~60-75% of the time. Perhaps it is a symptom of functional programming? A lot of function passing and anonymous functions make it difficult to generate a meaningful stack trace.


Clojure's stack traces are an issue with Clojure specifically, and how it's hosted on top of the JVM. A lot of the stack trace you get is actually implementation details of the Java objects making up the Clojure runtime. In effect, the program that you get stack traces of is the Clojure interpreter rather than your Clojure program which is running inside that interpreter.


Why do they do this, though? Shouldn't they have realized from the start that such messages are not helpful, and should have given messages related to your Clojure program? (Or is there some difficult technical issue related to achieving this?)

Asking because reading about this issue in the past is one thing that has kept me from trying out Clojure.


I've heard similar things about Scala, though I haven't had a chance to confirm this for myself yet. Not 100% sure if this supports your hypothesis or not given that Scala is multiparadigm?


Fortunately, I think 1.10 is going a long way towards fixing this.


My experience in Racket has been the opposite. Especially with the aid of DrRacket's stepping debugger, reading stack traces and finding bugs is rather painless. (Figuring out the best way to fix bugs, however, is no easier than in any other language.)


Functional programming not so much- languages like Elixir or JS used functionally don't have this problem generally.


Elixir has had difficult to parse error messages until relatively recently, but this has improved immensely (Dialyzer/Dialyxir in particular).


In what way? I've been using Elixir since late 2015 and have rarely had issues.


Yeah I agree. The way this thread is going you would think that all errors are easy and all you have to do is what the computer tells you and you’re done. I wish I’d known it was all that simple!


> stack traces that didn't make much sense.

Those can be especially prevalent in systems that utilize a lot of indirection.


Especially when you end up in C++ template hell.


That kind of stuff permanently damaged my ability to enjoy using C++.


Error in boost/bind.hpp:768


That's exactly what I felt as I was spending time on MSDN/Microsoft support website, reading about weird errors messages on Windows 95/98/NT/XP in 1990s. Some generic desc about the Windows error messages and no resolution.


as in tensorflow stack traces


And in the opposite direction: remember when you are writing error messages to include all the relevant details, and never ever write "this shouldn't happen" or "document later".


What about, log_panic("If we have somehow managed to hit this code path, this project if FUBAR. I would recommend giving up and starting over.")


Somehow reminds me of Aliens:

  I say we take off and nuke the entire site from orbit. It's the only way to be sure.
:-)


That's annoying but fine as long as it's unique and you can grep it in the codebase.


You can forgo something being unique if you just append line and file information to the log. Literally any logging framework (even homerolled ones) should give you this by default.


yup


If used correctly, «this should not happen» can be very useful, indicating e.g that the program is in some illegal state, as opposed to the input being incorrectly formatted.


Even if that’s the case, create a custom exception and embed in the custom exception object the actual exception.


Assert


That’s only true if the developer of the class module let the entire stack trace get through to the consumer.

In C# it’s the difference between...

try

{

....

}catch(Exception e)

{

//Do stuff

   throw new MyCustomException(“Something Bad happened”);
}

And

try

{

....

}catch(Exception e)

{

  //do stuff

   throw;

}


Erh, exception types should include an inner exception parameter, for the generic one they wrap. So neither of your two examples are all that great.


Why would I wrap an exception if I don’t plan to have special handling? If it is exception that I didn’t throw because of a business reason, why not just throw the original exception?


If you don't have any special handling, then why are you catching it at all?


That was the "//Do stuff" part, you may want to do some cleanup (in C# usually handled by a finally block or a "using" block), send a custom notification, logging (usually I would just let the client handle logging), etc.


In what case would you ever want the second example?


Always. If you can't resolve the exception and continue processing normally, you should never discard the exception you caught and create a new one of your own. If you must create one of your own, include the one you caught for the additional context.

It's pretty frustrating when you're debugging someone else's code and their error handling just throws away all of the useful information and replaces it with a generic "Something broke" kind of message.


usually you may catch a general exception and throw another one that's caught up the call stack. In this case i think it may be useful for logging additional causes that are not going to be obvious with just the stacktrace(?)


I remember once encountering an error that had all of the above plus it presented the solution to the issue right in the error message. It was amazing and why I still remember seeing that to this day.


Let's try that! I was trying to do some trivial task on a .gov website, but was greeted with the following, which I'm pasting here for your convenience. Could you spot the problem? Because their customer service can't.

  ---
Error Page Exception SRVE0260E: The server cannot use the error page specified for your application to handle the Original Exception printed below.

Original Exception: Error Message: javax.servlet.ServletException: /verification.xhtml at line 66 and column 34 action="#{verificationAction.authenticateClient()}": java.lang.NullPointerException Error Code: 500 Target Servlet: Faces Servlet Error Stack: javax.el.ELException: /verification.xhtml at line 66 and column 34 action="#{verificationAction.authenticateClient()}": java.lang.NullPointerException at org.apache.myfaces.view.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:95) at javax.faces.component._MethodExpressionToMethodBinding.invoke(_MethodExpressionToMethodBinding.java:88) at org.apache.myfaces.application.ActionListenerImpl.__AW_processAction(ActionListenerImpl.java:100) at org.apache.myfaces.application.ActionListenerImpl.processAction(ActionListenerImpl.java) at javax.faces.component.UICommand.broadcast(UICommand.java:120) at javax.faces.component.UIViewRoot._broadcastAll(UIViewRoot.java:995) at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:278) at javax.faces.component.UIViewRoot._process(UIViewRoot.java:1307) at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:733) at org.apache.myfaces.lifecycle.InvokeApplicationExecutor.execute(InvokeApplicationExecutor.java:34) at org.apache.myfaces.lifecycle.LifecycleImpl.__AW_executePhase(LifecycleImpl.java:172) at org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java) at org.apache.myfaces.lifecycle.LifecycleImpl.__AW_execute(LifecycleImpl.java:119) at org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java) at javax.faces.webapp.FacesServlet.__AW_service(FacesServlet.java:189) at javax.faces.webapp.FacesServlet.service(FacesServlet.java) at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1233) at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:782) at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:481) at com.ibm.ws.webcontainer.servlet.ServletWrapperImpl.handleRequest(ServletWrapperImpl.java:178) at com.ibm.ws.webcontainer.filter.WebAppFilterChain.invokeTarget(WebAppFilterChain.java:136) at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:97) at com.icbc.licensing.filter.ThreadContextFilter.__AW_doFilter(ThreadContextFilter.java:92) at com.icbc.licensing.filter.ThreadContextFilter.doFilter(ThreadContextFilter.java) at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:195) at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:91) at org.apache.logging.log4j.web.Log4jServletFilter.__AW_doFilter(Log4jServletFilter.java:71) at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java) at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:195) at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:91) at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:967) at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1107) at com.ibm.ws.webcontainer.servlet.CacheServletWrapper.handleRequest(CacheServletWrapper.java:87) at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:949) at com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1817) at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:200) at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:463) at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewRequest(HttpInboundLink.java:530) at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.processRequest(HttpInboundLink.java:316) at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:287) at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:214) at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:113) at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:175) at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217) at com.ibm.io.async.AsyncChannelFuture$1.__AW_run(AsyncChannelFuture.java:205) at com.ibm.io.async.AsyncChannelFuture$1.run(AsyncChannelFuture.java) at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1892) Caused by: java.lang.NullPointerException at com.icbc.licensing.clio.action.VerificationAction.DbAuthInsertandCount(VerificationAction.java:118) at com.icbc.licensing.clio.action.VerificationAction.__AW_authenticateClient(VerificationAction.java:161) at com.icbc.licensing.clio.action.VerificationAction.authenticateClient(VerificationAction.java) at sun.reflect.GeneratedMethodAccessor440.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:56) at java.lang.reflect.Method.invoke(Method.java:620) at org.apache.el.parser.AstValue.__AW_invoke(AstValue.java:268) at org.apache.el.parser.AstValue.invoke(AstValue.java) at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:278) at org.apache.myfaces.view.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:83) ... 46 more

Error Page Exception: Error Message: javax.servlet.ServletException: WebBeans context with scope type annotation @RequestScoped does not exist within current thread Error Code: 0 Target Servlet: Error Stack: javax.enterprise.context.ContextNotActiveException: WebBeans context with scope type annotation @RequestScoped does not exist within current thread at org.apache.webbeans.container.BeanManagerImpl.__AW_getContext(BeanManagerImpl.java:363) at org.apache.webbeans.container.BeanManagerImpl.getContext(BeanManagerImpl.java) at org.apache.webbeans.intercept.NormalScopedBeanInterceptorHandler.getContextualInstance(NormalScopedBeanInterceptorHandler.java:125) at org.apache.webbeans.intercept.NormalScopedBeanInterceptorHandler.invoke(NormalScopedBeanInterceptorHandler.java:96) at org.apache.webbeans.conversation.ConversationImpl_$$_javassist_0.isTransient(ConversationImpl_$$_javassist_0.java) at ...


verifcationAction.authenticateClient() call hit a null ref exception (called from the template at /verification.xhtml) and their error page is trying to use a webBean context which hasn't been setup or activated yet to display the error.

The original site of the null ref error seems to be the DBAuthInsert method at com.icbc.licensing.clio.action.VerificationAction.DbAuthInsertandCount(VerificationAction.java:118) so maybe a getConnection is returning a null and not being checked, or some config variable is borked. Would start digging at line 118 to work out what variables are being dereferenced and where their values come from.



The server process running in a thread other than the router? Dunno, I’m sure I could figure it out having access to the code. Support most likely does not employ software engineers / SREs.


In my experience, the progression of skill comes almost full circle. Juniors don't read error messages and try to debug "from first principles". Seniors pay attention to error messages. Experts often don't (initially) read the error message, because the very fact that there is an error immediately clues them in on its likely cause.


I had a candidate once. They were having trouble getting the message body on a 400 level error during the technical interview. They had chosen to solve it in Java. I'm not a Java developer (and I let the candidate know ahead of time and that I could only help with naive suggestions). Their exception message was pretty clear. After they prodded around for a bit getting nowhere, I pointed out the exception message. He ignored my suggestions multiple times (multiple angles of "your exception says blah"). After the interview, I took his solution and fixed it per the exception message. Boom. Worked. After the interview, his feedback to our recruiter was that it was obvious I did not know Java. Some people are bad at reading and listening :(. Also, this was a former Googler. It helped shatter an (unconscious?) bias that somehow Googlers were a breed above the rest.


In principle, I couldn't agree more. I get this from time to time, someone is stumped on an exception and after seeing it, I usually go "well, it's a null pointer exception in this method, so from looking at the code, it could come from these 3 places".

The pattern I see there is that a) in release builds, exceptions on many platforms suck. Things get inlined, parts of the stack trace are missing etc. If you understand why that is, that's not so much of a problem. But: b) people often have this Voodoo-like mentality about this. They often see the 100th stack trace that doesn't make much sense and try to wing it, because that's obviously always the case. The best thing you can do look at them together: Lead by example, think aloud and you might just teach someone how to read it in a better way.

It's rather important you have a consistent and accurate mental model of why your stack traces are mangled, lest you end up like one of those beasts that got random treats in B.F. Skinner's experiments and ended up with the strangest behaviors possible :-)


People never read error messages. Most of them click straight through 8 milliseconds after the error appears, without taking the slightest opportunity to understand.

It's rage-inducing when troubleshooting over laggy screensharing sessions. If enough frames drop, I may not even see that the error was raised.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: