die#
Raise an exception.
die throws an exception built from LIST. If the exception happens
inside an eval, the eval terminates with undef and $@ holds
the exception value. If nothing catches it, Perl prints the message
to STDERR and the interpreter exits with a non-zero status. The
exception can be a plain string, a list that stringifies into one,
or a reference — typically a blessed object carrying structured
error state.
Synopsis#
die LIST
die $message
die $exception_object
die # re-raise / propagate current $@
What you get back#
die does not return. Control transfers to the nearest dynamically
enclosing eval (which then returns undef in scalar context or
the empty list in list context), or — if there is no enclosing
eval — the interpreter unwinds, runs END and DESTROY handlers,
and exits.
The exception value itself lands in $@:
String exceptions — the stringified message, including any appended
at FILE line N.\n(see below).Reference exceptions — the reference itself, unchanged. This is the idiomatic way to throw a blessed exception object.
On uncaught exit, the exit code is derived from $! and $?:
exit $! if $!; # errno
exit $? >> 8 if $? >> 8; # child exit status
exit 255; # last resort
Rely only on the exit code being non-zero; the exact value is a best-effort encoding of whatever global error state was live at the moment of the throw.
Global state it touches#
$@— written with the exception on unwind into aneval, read by the no-argument form ofdieto propagate an existing exception, and read by the uncaught-exception printer.$!— read when deriving an exit code for an uncaught exception, and commonly interpolated into the message itself (die "open $f: $!").$?— read when deriving an exit code if$!is zero.ENDandDESTROYhandlers can still mutate it before the process actually exits.$.— the current input line number, appended to string exceptions that lack a trailing newline.$SIG{__DIE__}— if set, the handler runs before the exception is propagated, with the exception as its argument. The handler can replace the exception by callingdieagain with a different value.$^S— readable by$SIG{__DIE__}handlers to tell whether the die is happening inside aneval.
The trailing-newline rule#
Whether die appends location information depends on one character
at the end of the message:
Message ends in
"\n"— used verbatim. Nothing is appended. Use this form when the message is already a complete, user-facing diagnostic.Message does not end in
"\n"— Perl appends" at FILE line N", and if a file is being read,", <HANDLE> line M", then a final"."and newline. Use this form during development, or whenever locating thediecall in the source is more useful than a tidy message.
die "bad config\n"; # "bad config\n"
die "bad config"; # "bad config at script.pl line 42.\n"
A common idiom is to append ", stopped" to make the location
suffix read naturally:
die "/etc/games is no good, stopped";
# /etc/games is no good, stopped at canasta line 123.
Reference exceptions never get location information appended —
stringifying an object to inspect it would defeat the point of
throwing an object. If you want file and line inside a structured
exception, capture them at construction time (__FILE__,
__LINE__, or caller).
Reference-valued exceptions#
Passing a reference — typically a blessed object — lets $@ carry
structured state instead of a string you later have to parse:
package MyApp::Error;
sub new { my ($c, %a) = @_; bless { %a }, $c }
sub code { $_[0]{code} }
sub where { $_[0]{where} }
eval {
die MyApp::Error->new(code => 'EPARSE', where => 'line 12');
};
if (my $err = $@) {
if (ref($err) && $err->isa('MyApp::Error')) {
warn "parse error at ", $err->where;
}
else {
die $err; # not ours — re-raise
}
}
Overload stringification on exception classes so that an uncaught exception still prints a useful message:
use overload '""' => sub { "[MyApp::Error ".$_[0]->code."]\n" };
The stringified form should end in a newline and be non-empty, matching the treatment of string exceptions.
Because $@ is a global, copy it into a lexical before inspecting
it — any method call, ref, or isa you run during handling can
itself eval internally and clobber $@:
if (my $err = $@) { ... } # safe
if ($@) { $@->method; ... } # unsafe: method may reset $@
Propagation: die with no argument (or empty string)#
When LIST is empty or stringifies to "", die does not throw a
fresh exception — it re-raises whatever is in $@:
If
$@holds a string,dieappends"\t...propagated at FILE line N.\n"and re-throws. This is the canonical way to let an exception continue up the call stack after a partial-match check:eval { risky() }; die unless $@ =~ /Expected exception/;
If
$@holds an object reference with aPROPAGATEmethod, that method is invoked as$@ = eval { $@->PROPAGATE(__FILE__, __LINE__) }, and the return value replaces$@before the re-throw. ImplementPROPAGATEon an exception class when you want the exception to record the chain of re-raises.If
$@holds an object reference with noPROPAGATE, the reference is re-thrown unchanged.If
$@is also empty, the string"Died"is used.
The $SIG{__DIE__} hook#
Setting $SIG{__DIE__} installs a handler that runs when die
fires, with the exception as its argument. The handler can inspect
or replace the exception by calling die again with a different
value. It runs even inside eval, which is the usual reason to
want it out of the way:
local $SIG{__DIE__} = sub {
die @_ if $^S; # inside eval: do nothing special
log_fatal(@_); # outside eval: log before we exit
};
$^S is undef during compilation, true inside an eval, and
false at the top level — use it to gate handler work that only
makes sense for uncaught exceptions.
Examples#
Bail out with a clean message (note the trailing newline suppresses file/line appending):
chdir '/var/spool' or die "can't cd to spool: $!\n";
Die without a newline during development so the location is appended:
die "unexpected empty record";
# unexpected empty record at parse.pl line 87.
Catch a string exception:
eval {
parse($input);
};
if ($@) {
warn "parse failed: $@"; # $@ already ends in "\n" if the
# die'd message did
}
Throw and catch a blessed exception object:
eval {
die MyApp::Error->new(code => 'EIO', detail => $!);
};
if (my $err = $@) {
if (ref($err) && $err->isa('MyApp::Error')) {
handle($err);
}
else {
die $err; # re-raise anything unexpected
}
}
Conditional propagation — catch one class, let the rest through:
eval { work() };
die unless $@ =~ /^recoverable:/;
recover();
Edge cases#
List with two or more items is stringified and concatenated to form the message:
die "read failed on ", $file, ": $!". The newline rule applies to the concatenated result.Empty list (
die;ordie "";) triggers the propagation path described above, not a fresh exception.Reference with trailing newline inside the stringified form is irrelevant: location is never appended to a reference, regardless of what its
""overload produces.dieinsideDESTROYduring global destruction can still fire$SIG{__DIE__}but may not propagate as expected — the interpreter is already unwinding. Keep destructors defensive.Uncaught
dieduringENDblock runs remainingENDblocks but sets exit status per the$!/$?rule above.Nested
evaland$SIG{__DIE__}: the handler runs for every die, including those caught by an innereval. Guard with$^Sif the handler has side effects.Re-throwing the current
$@: prefer baredie;overdie $@;. The bare form triggers the propagation machinery (...propagatedsuffix,PROPAGATEhook);die $@does not — it treats$@as a fresh exception value.
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
eval— the only construct that catches adie; its block form traps exceptions into$@warn— same formatting rules (trailing-newline suppresses location), but writes toSTDERRand does not unwindcaller— capture file and line at throw time when building a structured exception objectexit— use when you want a specific exit code without the exception-handling machinery$@— where the exception lands after anevalcatches it, and the source the no-argdiere-raises from$SIG{__DIE__}— pre-throw hook that can inspect or rewrite the exception$^S— tells a$SIG{__DIE__}handler whether it is running inside aneval