The Dreaded Stack Trace
You crack your knuckles after a furious session of coding. Inspiration had struck like divine lightning, and you took advantage of the opportunity to code faster than you ever have before. You were in the zone, and for a few, brief, glorious moments, you felt like a 10x’er. Now, after the methods are complete and the classes wired up, you finally get to see the fruit of your labors.
You click the button on your screen…and your program explodes, taking with it your hopes and dreams of leaving by 5pm. A wall of text shoots by on your console sending seemingly random symbols and words scrolling past your screen.
Most would be intimidated and surrender. Luckily, you aren’t like most — you‘re here to figure out what you can do.
The stack trace is one of the most misunderstood and dreaded parts of software development for junior developers. It’s hard to blame them — it’s intimidatingly dense and filled with jargon and code words from deep within the core of systems. Experienced developers may have long forgotten the horror they once felt facing their first stack trace, but junior developers have yet to learn to embrace the stack trace for what it is — an incredibly useful tool for debugging issues.
So, what is a stack trace?
To put it simply, a stack trace describes the sequence of functions and events that led to a certain point in the execution of a program. To put it even more simply, when your program explodes, it tells you where it exploded and what steps it followed that led to the explosion. You can effectively use it as a map to debug your code.
The key to a stack trace is to understand what it is showing you.
A typical stack trace will show you:
- the error that occurred
- the sequence of classes and functions that led to the error
- the exact lines of code that were called
Scroll to the top of a stack trace. You’ll often see an exact error message describing what broke the program. If that doesn’t help, you can see, line by line, the functions that were called. You can keep scrolling to go deeper and see more inner errors that may have triggered the error.
Examples
Below is an example of a Java stack trace. Notice that the stack trace conveniently tells me the exact error that occurred and even gives me the name of the function, the name of the file/class, and the exact line of code to start my debugging. If I were to receive this stack trace, I’d start my search in Message.java
on line 23
in the getSubject()
method, looking for something that might lead to a NullPointerException
.
Exception in thread "main" java.lang.NullPointerException
at com.example.Message.getSubject(Message.java:23)
at com.example.Inbox.getMessages(Inbox.java:55)
at com.example.Main(Main.java:10)
You’ll notice this Ruby on Rails stack trace looks similar. It is indicating that my Postgres database server is either not running or not in the place Rails is looking.
0:22:19 rails.1 | /.rbenv/versions/2.2.4/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/postgresql_adapter.rb:671:in `initialize': could not connect to server: No such file or directory (PG::ConnectionBad)
10:22:19 rails.1 | Is the server running locally and accepting
10:22:19 rails.1 | connections on Unix domain socket "/tmp/.s.PGSQL.5432"?
10:22:19 rails.1 | from /.rbenv/versions/2.2.4/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/postgresql_adapter.rb:671:in `new'
10:22:19 rails.1 | from /.rbenv/versions/2.2.4/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/postgresql_adapter.rb:671:in `connect'
10:22:19 rails.1 | from /.rbenv/versions/2.2.4/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/postgresql_adapter.rb:217:in `initialize'
10:22:19 rails.1 | from /.rbenv/versions/2.2.4/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/postgresql_adapter.rb:37:in `new'
10:22:19 rails.1 | from /.rbenv/versions/2.2.4/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/postgresql_adapter.rb:37:in `postgresql_connection'
10:22:19 rails.1 | from /.rbenv/versions/2.2.4/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:721:in `new_connection'
10:22:19 rails.1 | from /.rbenv/versions/2.2.4/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:765:in `checkout_new_connection'
10:22:19 rails.1 | from /.rbenv/versions/2.2.4/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:744:in `try_to_checkout_new_connection'
10:22:19 rails.1 | from /.rbenv/versions/2.2.4/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:705:in `acquire_connection'
10:22:19 rails.1 | from /.rbenv/versions/2.2.4/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:501:in `checkout'
10:22:19 rails.1 | from /.rbenv/versions/2.2.4/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:364:in `connection'
10:22:19 rails.1 | from /.rbenv/versions/2.2.4/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:875:in `retrieve_connection'
Once you’ve seen one, you’ve seen them all — notice the similarities in this Javascript stack trace.
angular.js:13920 TypeError: Cannot read property 'toString' of undefined
at users-controller.js:13
at processQueue (angular.js:16383)
at angular.js:16399
at Scope.$eval (angular.js:17682)
at Scope.$digest (angular.js:17495)
at Scope.$apply (angular.js:17790)
at done (angular.js:11831)
at completeRequest (angular.js:12033)
at XMLHttpRequest.requestLoaded (angular.js:11966)
The Lesson
Stack traces are your friend — don’t be intimidated by them. They contain valuable information that‘ll help you solve your problem. Read them carefully and know what you’re looking for.