Jun 11, 2013

A Tale From the Grails trenches: Nasty 1.3.X Bug

grails_icon

Note: If this post help just one other person avoid the daylong head scratching session I recently went through It will be worth it.

It all starts early on a Monday moring. Just as I’m sitting down to start on what I had ‘planned’ to work on that day, my technical manager comes over and merely says to me:

Page XYZ was throwing errors all weekend.

bounce the server and it seems to be fixed, but can you look into it?

At this point 3 things go through my mind:

  1. There had not been any new code deployed to Production in over 3 weeks.
  2. It’s never a good sign when cycling a production server is the solution to any problem
  3. I need to stop being the first developer in on Mondays 🙂

After a half hour of looking at log files and trying to reproduce it on my local machine I came across this error:

org.codehaus.groovy.grails.web.taglib.exceptions.GrailsTagException: Tag [render]   is missing required attribute [template]

at com.bug.TestController$_closure2.doCall(TestController.groovy:12)

at com.bug.TestController$_closure2.doCall(TestController.groovy)

at java.lang.Thread.run(Thread.java:680)

This was very odd to me. Why was a GrailsTagException being thrown from my Contrller class? I know that you can invoke the GrailsTagLibs in a controller via the g attribute that gets injected, but my code was NOT using that.

Here is the code that was throwing the error:

try{
    def result = doSomething()
    render result as JSON
} catch(Exception ex) {
    def error = [error: 'There was an error""]
    render error as JSON, status: 503
}

Can you spot the error? Let’s look closely at this line in the catch block:

render error as JSON, status: 503

The render method on controllers have 2 main method signatures that you can use, one that takes a single param that can be something that you can write to the response like a simple string, or XML, or JSON. Another is one that takes a map, that can include: text, status, contentType, template, etc, all of which is marked as optional [render doc]

But our error message is saying that the template attribute is required?

If you look closely our suspect line of code above is trying to call a render method with as signature of:

render(JsonConverter, LinkedHashMap)

and this does not exist. So because this method does not exist, and we have all the power of Groovy at our disposal; the magic of method missing comes in to play and tries to go find a render method to match this description. Finally it comes to the g.render() method that is available via the GrailsTagLib.

Boom! This is where things go badly

Once Grails finds the render method on the Grails Tag Lib, which is a completly separate chunk of code from the controller render method, it then binds the TagLib render to ALL future calls to render on EVERY controller.

And because the template attribute is required in the Tag Lib version of render any call to render on any controller that dosn’t pass in a ‘template’ attribute will die a fiery death with a GrailsTagException.

The good news it that this bug has been addressed in Grails 2.x and above. I hope you never have to experience this one yourself but if you are stuck on the 1.3.x branch and do, I hope this post servers you well.

Here is a sample project that reproduces this issue in Grails 1.3.9 GitHub

 

About the Author

Object Partners profile.

One thought on “A Tale From the Grails trenches: Nasty 1.3.X Bug

  1. mike says:

    Thanks for sharing!

    1. Zan Thrash says:

      Lauri H

      The project I was on at the time was a fairly large multi-app system where the ROI on upgrading to 2.x was not there for the business.

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Blog Posts
Android Development for iOS Developers
Android development has greatly improved since the early days. Maybe you tried it out when Android development was done in Eclipse, emulators were slow and buggy, and Java was the required language. Things have changed […]
Add a custom object to your Liquibase diff
Adding a custom object to your liquibase diff is a pretty simple two step process. Create an implementation of DatabaseObject Create an implementation of SnapshotGenerator In my case I wanted to add tracking of Stored […]
Keeping Secrets Out of Terraform State
There are many instances where you will want to create resources via Terraform with secrets that you just don’t want anyone to see. These could be IAM credentials, certificates, RDS DB credentials, etc. One problem […]
Validating Terraform Plans using Open Policy Agent
When developing infrastructure as code using terraform, it can be difficult to test and validate changes without executing the code against a real environment. The feedback loop between writing a line of code and understanding […]