Skip to content
VLSI Mentor

Perl Part I · Module 14 · Errors, Warnings, and Debugging

Carp: croak, carp and confess

You write a small helper that validates a slack value. Somebody calls it with rubbish and it dies, and the error message points at the line inside your helper — the one line in the program you are already confident about. What you actually need to know is which of the forty places that call it passed the rubbish, and die will not tell you. Carp is the core module that fixes this. It gives you three functions that report a problem at the caller's line instead of your own, and a fourth option that prints the entire call chain when the immediate caller is not where things went wrong either. This chapter measures all of it against a real module on disk, because the whole point is which file the message names.

Intermediate14 min readPerlPart IDebugging

Part I · Module 14 · Chapter 14.9 · Carp: croak, carp and confess

1. The Problem: die Blames The Wrong File

Everything below uses this module, saved as lib/VLSI/Slack.pm. It has two near-identical functions that differ only in how they object.

Azvya Education Pvt. Ltd.VLSI Mentor
lib/VLSI/Slack.pm
package VLSI::Slack;

# A small helper module, used by every example in this chapter. The first two
# functions are identical except for how they object to bad input: one uses
# die, the other uses croak. The line numbers below appear in the output.

use strict;
use warnings;
use Carp qw(carp croak confess);

sub looks_numeric { return $_[0] =~ /\A-?[\d.]+\z/ }

sub with_die {
    my ($value) = @_;
    die "bad value '$value'" unless looks_numeric($value);
    return $value;
}

sub with_croak {
    my ($value) = @_;
    croak "bad value '$value'" unless looks_numeric($value);
    return $value;
}

sub with_carp {
    my ($value) = @_;
    carp "bad value '$value', using 0" unless looks_numeric($value);
    return looks_numeric($value) ? $value : 0;
}

sub report    { return summarise(@_) }
sub summarise { confess "bad value '$_[0]'" }

1;

Now call the first two from a script and compare the messages:

Azvya Education Pvt. Ltd.VLSI Mentor
die-vs-croak.pl
use strict;
use warnings;
use lib "lib";
use VLSI::Slack;

eval { VLSI::Slack::with_die("abc") };
my $from_die = $@;
$from_die =~ s/\s+\z//;

eval { VLSI::Slack::with_croak("abc") };
my $from_croak = $@;
$from_croak =~ s/\s+\z//;

print "die   -> $from_die\n";
print "croak -> $from_croak\n";
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
die   -> bad value 'abc' at lib/VLSI/Slack.pm line 15.
croak -> bad value 'abc' at die-vs-croak.pl line 10.

That is the entire chapter in two lines.

die named lib/VLSI/Slack.pm line 15 — the line inside the module. True, and useless. You wrote that line; it is doing exactly what you told it to.

croak named die-vs-croak.pl — the line in the calling script. That is the line that passed "abc", and it is the line you need to look at.

Note that neither message has a trailing newline in the module source. That is deliberate and it is Chapter 14.2's rule applied: a message ending in \n prints exactly as written and gets no location at all, which would defeat the entire comparison. For croak you nearly always want the location, so you nearly always leave the newline off.

2. The Three Functions

They map onto things you already know:

You knowCarp versionWhat changes
warncarpreports at the caller's line
diecroakdies at the caller's line
dieconfessdies with the whole call chain

So carp is to warn what croak is to die. Both keep the behaviour and move the blame.

Azvya Education Pvt. Ltd.VLSI Mentor
carp-and-croak.pl
use strict;
use warnings;
use lib "lib";
use VLSI::Slack;

# carp: warns at the caller, and the script CONTINUES
my @collected;
{
    local $SIG{__WARN__} = sub { push @collected, $_[0] };
    my $value = VLSI::Slack::with_carp("abc");
    print "with_carp returned '$value' and the script continued\n";
}
my $warning = $collected[0] // "(none)";
$warning =~ s/\s+\z//;
$warning =~ s/\bat \S+ line (\d+)/at THIS-SCRIPT line $1/;
print "the warning was: $warning\n";

# croak: dies at the caller, so it must be caught to carry on
my $ok = eval { VLSI::Slack::with_croak("abc"); 1 };
my $err = $@;
$err =~ s/\s+\z//;
$err =~ s/\bat \S+ line (\d+)/at THIS-SCRIPT line $1/;
print "\ncroak survived? ", ($ok ? "yes" : "no"), "\n";
print "the error was:   $err\n";
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
with_carp returned '0' and the script continued
the warning was: bad value 'abc', using 0 at THIS-SCRIPT line 10.

croak survived? no
the error was:   bad value 'abc' at THIS-SCRIPT line 19.

with_carp warned and returned a value — 0, its deliberate fallback — so the script carried on. with_croak died and needed an eval to survive, exactly as Chapter 14.2 described for warn and die. Both messages name the calling script rather than the module.

The choice between them inside a module is the same judgement as Chapter 14.2's, with one addition:

  • croak when the caller has broken the contract. A required argument is missing, a value is the wrong type, a file they named does not exist. They cannot be allowed to continue, and the fault is at their call site.
  • carp when you can proceed but they should know. A deprecated argument, a default being substituted, a value outside the expected range but still usable.
  • Plain die for a problem inside your own module — an assertion about your own state, a case you believe is unreachable. Here the module's own line number genuinely is the right place to point, because the bug is yours.

That last point is the one people miss. croak is not simply "the better die". It is the right tool when the caller is at fault, and the wrong tool when you are.

3. confess, When The Caller Is Not The Culprit

croak moves the blame exactly one level up. Sometimes that is still not far enough.

Azvya Education Pvt. Ltd.VLSI Mentor
confess-trace.pl
use strict;
use warnings;
use lib "lib";
use VLSI::Slack;

# report() calls summarise(), which confesses
eval { VLSI::Slack::report("abc") };
my $trace = $@;

# make the script's own name and the line numbers stable for comparison
$trace =~ s/\bat \S*confess-trace\.pl line \d+/at THIS-SCRIPT line N/g;
print $trace;
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
bad value 'abc' at lib/VLSI/Slack.pm line 32.
	VLSI::Slack::summarise("abc") called at lib/VLSI/Slack.pm line 31
	VLSI::Slack::report("abc") called at THIS-SCRIPT line N
	eval {...} called at THIS-SCRIPT line N

That is the full chain, innermost first:

  • the confess itself, inside summarise
  • summarise was called by report
  • report was called by the script
  • and the eval that wrapped it

With croak, you would have learned only that report was called from the script — which you knew. The trace tells you the path, and when a utility is called from six places through three layers of helpers, the path is the answer.

The arguments are included too, which is often the most useful part: summarise("abc") shows the bad value travelling down the chain, so you can see where it entered.

Two practical notes:

confess is for development, not production messages. A user running a report does not want a stack trace; they want one clear sentence. Use croak for errors they will see and confess for errors that mean your code is broken.

longmess and shortmess give you the text without dying. Carp::longmess("note") returns the same trace as a string, which is useful inside a $SIG{__WARN__} handler when you want to know where a warning came from without changing the script's behaviour — the Chapter 14.6 suggestion, in its concrete form:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
local $SIG{__WARN__} = sub { print STDERR Carp::longmess($_[0]) };

That one line turns every warning in the run into a warning plus a trace, which finds the source of an uninitialized value complaint faster than anything else in this module.

4. Choosing, And One Thing To Watch

A short decision list:

  • Inside a module, caller's fault, cannot continue → croak
  • Inside a module, caller's fault, can continue → carp
  • Inside a module, my own bug → die, or confess while developing
  • In a top-level script → plain die and warn; there is no caller to blame, so croak has nothing to point at that die would not

One more habit worth adopting. A croak message should name the value that was wrong:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
croak "slack value '$value' is not numeric"     # good: shows what arrived
croak "invalid argument"                        # bad: you now have to go and look

The location tells you where; the message has to tell you what. Chapter 14.7's point about Perl's own warnings applies to the ones you write: Use of uninitialized value $slack{"B"} is useful precisely because it names the key.

5. What To Remember

  • die inside a helper blames the helper. Measured: at lib/VLSI/Slack.pm line 15 — the one line you already trust.
  • croak blames the caller. Measured: the same rejection reported the calling script's line instead.
  • carp is to warn what croak is to die — same behaviour, blame moved one level up.
  • Measured: with_carp returned its fallback and the script continued; with_croak needed an eval.
  • Leave the trailing \n off a croak message, or Perl prints it verbatim and you lose the location — which is the only reason you used croak.
  • Carp is core, so it needs nothing installed.
  • Use croak when the caller is at fault and plain die when the bug is yours — croak is not just a better die.
  • confess prints the whole call chain, with arguments. Measured: four frames from the confess out to the eval.
  • confess is for development; users want one sentence, so give them croak.
  • Carp::longmess returns the trace without dying — put it in a $SIG{__WARN__} handler to find where a warning came from.
  • In a top-level script, plain die and warn are correct — there is no caller to blame.
  • @CARP_NOT fixes a message that points inside your own distribution across package boundaries.
  • Name the bad value in the message. The location says where; only you can say what.

Chapter 14.10 picks up the tool this module has been working around. When printing is not enough — when you need to stop a running script, look at a structure, change a value and carry on — that is the debugger, and perl -d is already installed.

Where this fits

Part of the Perl curriculum.