When null is not null

What follows is the saga of a bug that took about 2 hours to pinpoint and 5 minutes to fix. It reminds me of one reason I some find dynamically typed languages annoying: implicit casting.

Here's the scenario: The manager tells me he noticed some weird output on one web page. Specifically, this one particular field, which should be empty, is showing the word "null." I own this field, so it's my job to fix it.

Naturally, I start by looking at the code. The site is written in PHP, so I figured that the field is null in the database and PHP is just printing out the word instead of the empty string, as I'd expect. But that's not it. There's actually already a check for null in the data retrieval code. So, just to check, I look at the relevant row in the database. And guess what - the field in question has the value "null." And just to be clear, I don't mean the field is null, I mean it contains "null" - as a string.

Now the plot thickens. This row is user-submitted content. This particular field has a default value of NULL (that's actual, database null) and users need special permissions in the application to add or edit it. The user in question does not have these. Another check of the database reveals that there are a number of similar records, submitted by users without the proper permissions, that have the string "null" in this field. However, it's not all of them, which means it's not related to the default field value. So something is weird.

Off the top of my head, I knew that there are only two places in the code where a user can set that field. One was the main submission form, the other was an AJAX-based update page. A quick check of the database revealed that the updated timestamps on the affected records were empty, so naturally I concentrated on the submission form. Of course, this turned out to be the wrong decision, as the submission form was correct. It turns out that the updated timestamps for user-submitted records never actually got updated.

So I checked out my other possibility - the AJAX update page. It turns out that the server-side code was correct. The null was actually coming from the JavaScript!

When I added the problem field to this page, I made one bad mistake. You see, since only privileged users can edit the field in question, I decided that the server-side code would simply not put it on the page for non-privileged users. That's fine. However, I failed to account for the dynamically-created edit boxes. You see, because this page is actually a listing page with an edit feature, we were actually dumping the database field values into DIVs and then replacing these DIVs with input boxes when the user clicked the "edit" link. We then took the values of those boxes and sent an HTTP request to the server.

Well, if you're paying attention, you may see what happened. I wasn't careful with my JavaScript. When I added the ability to edit this one field, I didn't check if it actually existed in the page. I just used our JavaScript framework to grab the value and then dump it into the POST data I was sending to the server. Well, if the DIV for that field didn't exist, then the value I got back was null. And when I put that in the POST data, it was type-cast to the string "null." So, when the server-side page got the data, it saw that string, not the empty object value, and dutifully stored it in the database.

The moral of the story: when working in a weakly-typed language, you still have to be careful about your variable types. In fact, you have to be more careful. Because the compiler/interpreter won't help you find problems and you can't always count on implicit conversions being done the way you mean. Especially in JavaScript.

You can reply to this entry by leaving a comment below. You can send TrackBack pings to this URL. This entry accepts Pingbacks from other blogs. You can follow comments on this entry by subscribing to the RSS feed.

Add your comments #

A comment body is required. No HTML code allowed. URLs starting with http:// or ftp:// will be automatically converted to hyperlinks.