Added: Thanks, tye++ and leriksen++. You showed me something I didn't really understand before. It looks like builtins are outside both lexical and dynamic scope, being resolved sometime while compiling. Localizing them has no effect, and the last-compiled override is the one which counts. It's still a little freaky:

As tye pointed out, you can override it in a BEGIN statement. But there is a point here, rewriting error messages like this is potentially evil. Error handling code very often depends on error messages being caught by eval and then parsed for certain constructs. Using $SIG{__DIE__} or die() to modify the messages potentially can interfere with this process.

The trick is to not use die(), and excise it from the code. Use your own subroutine (with its own name) and do whatever you like. People know to expect something different when they see a user defined subroutine name, but they most always expected documented behaviour when they see a Perl built-in.