Author image Eduardo Santiago Muñoz


CGI::Alert - report CGI script errors to maintainer


    use CGI::Alert 'youraddress@your.domain';

That's all. Everything else is transparent to your script.


    use CGI::Alert qw(you@your.domain http_die);
    my $foo = param('foo')
      or http_die '400 Bad Request', '<b>foo</b> param missing';

The http_die function provides a one-call mechanism for emitting an HTTP error status with a helpful message. This is intended mostly for handling assert-style situations: you want to make sure you don't continue past a bad point.


CGI::Alert will inform you by email of warnings and errors (from die or from exiting with nonzero status).

If the script terminates normally (exit status 0), and no warnings were issued by the script or by Perl, CGI::Alert is a no-op. It just consumes resources but has no other effect.

If the script terminates normally, but has issued warnings (either directly via warn, or by Perl itself from the warnings pragma), CGI::Alert will send you an email message with the first 10 of those warnings, plus other details (see below).

If the script terminates via die, CGI::Alert sends you an email message with the details. It also displays a big 'Uh-Oh' on the remote web user's browser, informing him/her that an error has occurred, and that the maintainer has been notified.

CGI::Alert is useful for letting you know of problems in your scripts. It's also useful for adding FIXMEs: you can leave unimportant-seeming sections unimplemented, but put a "warn" statement in them. If you get email from that section, you know your users have a need for that functionality.

Maintainer Address

To specify the email address that will be notified of problems, include it in the import list:

    use CGI::Alert '';

or, more typically:

    use CGI::Alert 'esm';   # where 'esm' is a local account

Hiding Sensitive Data

Forms often contain sensitive data: passwords, credit card numbers, next Tuesday's winning Lotto numbers. CGI::Alert sends unencrypted email, and you don't want these values being intercepted.

To exclude CGI parameters from the list sent by email, use the hide=qr/.../ keyword on the import line:

    use CGI::Alert 'esm', 'hide=qr/credit/i';

If CGI::Alert encounters any parameter matching the given regex, it substitutes [...] (bracket, ellipsis, bracket) for its value:

    card_type       = Visa
    card_name       = Joe Bob
    credit_card_num = [...]

Multiple expressions are allowed, but must be specified using one hide= for each:

    use CGI::Alert 'esm', 'hide=qr/credit/i', 'hide=qr/passphrase/';

The default exclusion list is qr/(^|[\b_-])passw/i

Running under tilde URLs

CGI::Alert checks the REQUEST_URI environment variable. If it detects a URL of the form /~something (slash, tilde, something) CGI::Alert overrides the maintainer address, sending email only to the something following the tilde.

Specifics: email

On any die, or if the CGI script has issued warnings, CGI::Alert sends an email message to the maintainer with the following details:

  • The URL used to access the page

  • The error message emitted by die, with complete stack trace.

  • Any warnings issued by the script (well, just the first 10), with full stack trace.

  • The remote user name (if known) and host name/address

  • A full list of CGI parameters passed to the script. CGI::Alert relies on the param function provided by for this.

  • A full list of process environment variables and their settings.

  • The expanded results of %INC, showing all loaded modules and their paths. This can help when the problem is an obsolete version of a module.

Specifics: WWW

If the script dies, a large heading will be shown in red typeface, saying "Uh-Oh!". The error will be displayed, along with a note saying that the maintainer has been notified by email.

The remote (web) user is not informed of warnings.


CGI::Alert provides one exportable function (not exported by default):

  • http_die ['--no-alert',] HTTP Status, Blurb for User

    http_die provides a simple way for you to assert a condition and provide a safe way to handle assertion failure.

    For example, if your CGI script is guaranteed always to be called with the item_number parameter set, you can write:

        my $item = param('item_number')
          or http_die '400 Bad Request','Missing item_number param';
        $item =~ m!^([a-z][a-z0-9]+)$!
          or http_die '400 Bad Request',"Bad item number '$item'";
        $item = $1; # untaint.  We've validated that it's correct.
        exists $Catalog{$item}
          or http_die '--no-alert','404 Not Found',"$item: No such item";

    This lets you guard against people trying to sneak in with forged requests. It also lets you check for "can't possibly happen" conditions in your code. Not that these ever happen.

    http_die uses warn on its input, to make sure it goes to the server log. This means you also get email notification when it happens. To prevent getting an email notification on common occurrences (such as the 404 above), use --no-alert as the first argument to http_die.

Custom Headers

You want your error messages to conform to your site standards: stylesheets, etc.

http_die() will use start_html if is loaded. You can pass extra arguments to start_html via extra_html_headers() :

    use CGI::Alert ('yourname', 'http_die');

    # We issue these below, when we call start_html()
    our @Common_Headers = (
                -author  => '',
                -head    => Link({-rel  => 'shortcut icon',
                                  -href => '/my.ico',
                                  -type => 'image/x-icon',
                -style   => {
                             -src  => '/my.css',

    # If we ever call http_die(), make it use the above
    CGI::Alert::extra_html_headers( @Common_Headers );

Custom Browser Text

In the event of a die(), CGI::Alert will display the following message to the remote (browser) user:

  <h1><font color="red">Uh-Oh!</font></h1>
  The script which was handling your request died, with the following error:
  If that indicates a problem which you can fix, please do so.

...where [MSG] gets replaced with the error from die().

Use CGI::Alert::custom_browser_text to customize the text message displayed to the remote user (the browser). The simple way is to pass a string:

  # Show custom text to remote viewer
  CGI::Alert::custom_browser_text << '-END-';
  We crashed with: <blink>[MSG]</blink>

As above, [MSG] (open bracket, upper-case MSG, close bracket) will be replaced with the die() text.

Or, if you want fine-grain control, you can pass a CODE ref:

  # Your function must take TWO arguments
  sub my_text_func($$) {
    my $msg = shift;                      # in: Perl error message
    my $emit_http_headers = shift;        # in: Emit HTTP status?

    if ($emit_http_headers) {
      print  "Status: 500 Server Error\n"
             "Content-type: text/html; charset=ISO-8859-1\n",

    if ($msg =~ /frobbledygrunt/) {
      # something special
    else {
      print "<h1>Ouch!</h1>\n",
            "<p>Died with:</p>",
            "<div class='foo'>",$msg,"</div>\n";

    # Important!  Return 1, to tell CGI::Alert we were successful
    return 1;

  CGI::Alert::custom_browser_text \&my_text_func;

See Also

For a description of HTTP error status codes, see:


CGI::Alert requires a properly configured sendmail executable in /usr/sbin or /usr/lib. This does not need to be Sendmail itself: Postfix, Exim, and other MTAs provide this executable.


If the script dies before emitting the 'Status' and 'Content-Type' headers (e.g. because of a compile-time syntax error), the remote user will see the dreaded '500 Server Error' page. Since this only really happens when the CGI script fails to compile, this will only ever be seen by the CGI script developer and hence is not a big deal.

As a workaround for this, you can do:


This tells CGI::Alert to emit HTTP Status and Content-type headers before displaying the Uh-Oh message.


Ed Santiago <>

2 POD Errors

The following errors were encountered while parsing the POD:

Around line 904:

You forgot a '=back' before '=head2'

Around line 996:

=back without =over