Exception - structured exception handling for Perl


    use Exception qw(:all);

    my $err=new Exception 'id';

    try {
      $err->raise('error text');
      die 'dead';
    } when $err, except {
        my $error=shift;
      when 'die', reraise
      except {shift->croak}
      finally {
        print STDERR "Tidying up\n";


This module fulfils two needs; it converts all errors raised by die to exception objects which may contain stack trace information and it implements a structured exception handling syntax as summarised above.

What You Get Just by Loading the Module

Exception installs a $SIG{__DIE__} handler that converts text passed to die into an exception object. Stringification for the object is mapped onto the confess method which, by default, will simply print the error text on to STDERR.

Structured Exception Handling

Exception allows you to structure your exception handling; code that can directly or indirectly raise an exception is enclosed in a try block, followed by except blocks that can handle specific exceptions or act as a catch-all handler for any exceptions not otherwise dealt with. Exceptions may be propagated back to outer contexts with the possibility of adding extra information to the exception, and a finally block can also be specified, containing tidy-up code that will be called whether or not an exception is raised.

Exception handling blocks can be tied to specific exceptions by id, by exception object or by regexp match against error text. The default exception display code can be augmented or replaced by user code.

Stack Tracing

Exception can be persuaded to capture and display a stack trace globally, by exception object or explicitly when an exception is raised. You can capture just the context at which the exception is raised, a full stack trace or an absolutely full stack trace including calls within the Exception module itself.


Exception will create an exception object when it traps a die. More flexibly, user-created exception objects can be raised with the raise method.

Each exception object has an id; a text string that is set when the object is created (and that can be changed using the id method thereafter). die exceptions have the id 'die', anonymous exceptions created at raise time have an empty id. The exception id is set initially by a parameter to the exception constructor:

  my $err=new Exception 'id';

Exceptions are raised by the raise method:

  $err->raise('error text');



for an anonymous exception.


Code to be protected by Exception is enclosed in a try {} block. Any die or raise event is captured; what happens next is up to you. In any case, you need to import the routines that implement the exception structuring:

  use Exception qw(:try);

is the incantation. Either that or one of qw(:stack), qw(:debug) or qw(:all) if you need stack frame, debug or both facilities as well.

Default Behaviour

If no exception handling code is present, the exception is reraised and thus passed to the calling block; this is, of course, exactly what would happen if try wasn't present at all. More usefully, the same will happen for any exceptions raised that aren't matched by any of the supplied exception blocks.

If no user-supplied exception handler gets called at all, Perl will display the exception by stringifying it and terminate the program.

Trapping Exceptions

except blocks match all or some exceptions. You can define as many as you like; all blocks that specifically match an exception are called (unless an earlier except block raises an exception itself), default blocks are only executed for otherwise unmatched exceptions.

In either case, the except block is passed two parameters: the exception object and the current return value for the entire try construct if it has been set.

Use the when clause to match exceptions against except blocks:

  try {<code>} when <condition>, except {<handler>};

Conditions may be text strings, matching the id of an exception, regexp refs, matching the text of an exception, or exception objects, matching the given exception object or clones thereof. Multiple conditions may be specified in an array ref; the except block will apply if any of the conditions match.

For example:

  my $err=new Exception 'foo';

  try {
  } when ['foo', qr/bar/, $err], except {

will match on all three conditions.

Reraising Exceptions

Exceptions can be passed to a calling context by reraising them using the reraise clause. reraise can be tied to specific exceptions using when exactly as for except.

For example:

  try {
  } when 'die', reraise
    except {
      <other exceptions>

would pass exceptions raised by die to the calling routine.

Transforming Exceptions

It is sometimes useful to change the id of an exception. For example, a module might want to identify all exceptions raised within it as its own, even if they were originally raised in another module that it called. The as method performs this function:

  my $myErr=new Exception 'myModule';

  try {
    <calls to other code that might raise exceptions>
    <local code that might raise $myErr exceptions>
  } when $myErr, reraise
    except {
      shift->as($myErr)->raise('extra text');

This will pass locally raised exception straight on; other exceptions will be converted to $myErr exceptions first. The error text parameter to the raise can be omitted: if so, the original error text is passed on unchanged. Adding extra text can however be useful in providing extra contextual information for the exception.

Using an exception object as the parameter to as in this way replaces the id, debugLevel and confessor properties of the original exception. as can also be passed a text string if only the id of the exception needs changing.

Finalisation Blocks

One or more finally blocks can be included. These will all be executed always regardless of exceptions raised, trapped or reraised and can contain any tidy-up code required - any exception raised in an except block, reraised or not handled at all will be raised after all finally blocks have been executed:

  try {
  } except {
      <exception handling>
    finally {
      <housekeeping code>

The finally blocks are passed two parameters, the exception (if any) and the current return value (if any) in the same way as for except blocks.

Return Values

try constructs can return a (scalar) value; this is the value returned by either the try block itself or by the last executed except block if any exception occurs, passed though any finally blocks present.

For example:

  my $value=try {
    return 1;
  } except {
      return 0;
    finally {
      my ($error, $retval)=@_;
      return $retval;

will set $value to 1 or 0 depending on whether an exception has occured. Note the way that the return value is passed through the finally block.


Exception can be persuaded to capture and display a stack trace by any one of four methods:

  1. by setting the environment variable _DEBUG_LEVEL before starting your Perl script.

  2. by setting the package default with Exception->debugLevel(DEBUG_STACK).

  3. by setting the debug level explicitly in an error object when you create it:

      my $err=new Exception 'foo';
  4. by setting the debug level when you raise the exception:

      $err->raise("failed: $!", {DEBUGLEVEL=>DEBUG_ALL});

Each of these will override preceding methods. The default default is no stack capture at all.

The debug level can be set to:


no stack trace is stored.


only the location at which the exception was raised is stored.


a full stack trace, excluding calls within Exception, is stored.


a full stack trace, including calls within Exception, is stored.

You need to import these constants to use them:

  use Exception qw(:debug);
  use Exception qw(:all);

will do the trick.

Note that these controls apply to when the exception is raised - the display routines will always print or return whatever stack information is available to them.



  my $err=new Exception 'id', 'error text';
  my $new=$err->new('id2', 'error text');

This method either creates a new exception from scratch or clones an existing exception.

The first parameter is an exception id that can be used to identify either individual exceptions or classes of exceptions. The optional second parameter sets the text of the exception, this can be added to when the exception is raised. The default is no text.


  open FH, "<filename"
    or $err->raise("can't read filename: $!");

Raise an exception. That's it really. If raise is applied to an existing exception object as above, the text supplied is added to any pre-existing text in the object. Anonymous exceptions can also be raised:


but the use of predeclared exception objects is encouraged.


  $err1->as('new id');

Transform an exception object either from another template exception, which will change the object's id, debug level and confessor, or by name, which will just change the id of the exception.

as returns the exception object, so a further method (typically raise) may be applied in the same statement:



  my $text=$err->text;
  my @text=$err->text;
  my $textAndStack=$err->text(2);

Return the text and, optionally, any saved stack trace of an exception object. text can take a parameter (which defaults to 0) and can be called in scalar or list context:

  param  scalar                      list

  0      line1 \n line2 \n           (line1, line2)
  1      line1 \n line2              (line1, line2)
  2      line1 \n line2 \n stack \n  (line1, line2, stack)

Be careful about context: print $err->text; probably won't do what you want; you almost certainly meant print scalar($err->text);.

An exception gains a line every time it is raised with a text parameter. Actually, to be precise, raise creates a new exception object with the extra line, but that's the sort of implementation detail you don't need to know, unless of course you want to...


  my $stack=$err->stack;

Return the stack trace data (if any) for an exception. The stack is returned as a reference to an array of stack frames; each stack frame being a reference to an array of data as returned by caller. The stack frame elements can be indexed symbolically as FRAME_PACKAGE, FRAME_FILE, FRAME_LINE, FRAME_SUBNAME, FRAME_HASARGS and FRAME_WANTARRAY. FRAME_LAST is defined as the index of the last element of the frame array for convenience.

To use these names, you need to import their definitions:

  use Exception qw(:stack);
  use Exception qw(:all);

will do what you want.


  my $level=$err->debugLevel;
  my $defaultLevel=Exception->debugLevel;
  my $old=$err->debugLevel($new);
  my $oldDefault=Exception->debugLevel($newDefault);

Get or set the stack trace level for an exception of object or the package default. See the section above.


  my $code=$err->confessor;
  my $defaultCode=Exception->confessor;
  my $old=$err->confessor($new);
  my $oldDefault=Exception->confessor($new);

Get or set code to display an exception. The routines all return a reference to an array of coderefs; the routines are called in sequence when an exception's confess or croak methods are invoked.

If confessor is passed a coderef, the code is added to the end of the array (the routines are actually called last to first); if confessor is passed a reference to an array of coderefs, the array is replaced by the one given. As a special case, if the array given is empty, the set of confessor routines is reset to the default.

A confessor routine is passed two parameters when called: the exception object and a quiet flag; if this is non-zero, the routine is expected not to produce any output. The routine should return the new value of the flag: 0, 1 or -1, the last telling Exception to not call any further display routines at all.

As a trivial example, here's the default routine provided:

  sub _confess($$) {
    my ($error, $quiet)=@_;
    print STDERR (scalar $error->text(2)) unless $quiet;


  my $id=$err->id;
  my $defaultId=Exception->id;
  my $old=$err->id($new);
  my $oldDefault=Exception->id($new);

Get or set the id of an exception, or of the package default used for anonymous exceptions. Exception ids can be of any scalar type - Exception uses text strings for those it generates internally ('die' for exceptions raised from die and, by default, '' for anonymous exceptions) - but you can even use object references if you can think of something useful to do with them, with the proviso that when uses a simple eq test to match them; you'll need to overload eq for your objects if you want anything clever to happen.


  my $exitcode=$err->exitcode;
  my $defaultExitcode=Exception->exitcode;
  my $old=$err->exitcode($new);
  my $oldDefault=Exception->exitcode($new);

Get or set the exit code returned to the OS by croak. This defaults to 1.



Display the exception using the list of confessor routines it contains. By default, this will display the exception text followed by the stack trace (if one exists) on STDERR.



Call the exception's confess method and terminate. If no exit code is supplied, exit with the exception's exit code as set by the exitcode method.


The module can interact in unpredictable ways with other code that messes with $SIG{__DIE__}. It does its best to cope by keeping and propagating to any die handler that is defined when the module is initialised, but no guarantees of sane operation are given.

finally blocks are always executed, even if an exception is reraised or an exception is raised in an except block. No problem there, but this raises the question of what to do if another exception is raised in the finally block. At present Exception merges the the second exception into the first before reraising it, which is probably the best it can do, so this probably isn't a bug after all. Whatever.

Need More Tests.


Pete Jordan <>