libapa...:Error(3pm)

πŸ’– APR::Error β€” the manual, but make it make sense πŸ’–

from the User Contributed Perl Documentation, living in libapa...:Error(3pm)


🌸 NAME 🌸

APR::Error β€” the Perl API for APR/Apache/mod_perl exceptions. She catches, you decide. πŸ’…


✨ SYNOPSIS ✨

eval { $obj->mp_method() };
if ($@ && $ref $@ eq 'APR::Error' && $@ == $some_code) {
    # handle the exception
}
else {
    die $@; # rethrow it
}

🫢 DESCRIPTION 🫢

Okay so bestie, APR::Error handles APR/Apache/mod_perl exceptions for you, while leaving you in control. Main character energy, but she's not stealing your spotlight. πŸ‘‘

Here's the tea: Apache and the APR API return a status code for, like, almost all methods. So if you didn't check that return code and handle every possible problem, you get silent failures β€” which can spiral into all kinds of obscure problems later. And on the flip side? Checking the status code after every single call is just too much of a kludge. It makes quick prototyping/development almost impossible, and we're not even gonna talk about code readability. And having methods return status codes also complicates the API if you need to return other values too. Messy.

So, to keep things nice and make the API readable, they decided not to return status codes, but instead throw exceptions with APR::Error objects for each method that fails. πŸŽ€ And here's the slay part: if you don't catch those exceptions, everything works transparently β€” perl will intercept the exception object and die() with a proper error message. So you get all the errors logged without doing any work. Iconic.

Now. In certain cases you don't wanna just die β€” you want the error trapped and handled. For example, if some IO operation times out, maybe it's totally fine to trap that and try again. But if we were to die with an error message, you'd have had to match the error message itself, which is ugly, inefficient, and may not work at all if locale error strings are involved. 😭 So instead you need to be able to get the original status code that Apache or APR generated. And the exception objects give you that if you want it. Even better β€” the objects carry extra info, like the function name (super useful in case you were eval'ing several commands in one block), plus the file and the line number where that function was invoked from. More attributes could be added in the future. She's always growing. πŸ¦‹

APR::Error uses Perl operator overloading, such that:

  • in boolean and numerical contexts, the object returns the status code;
  • in the string context, the full error message is returned.

When you're intercepting exceptions you need to check whether $@ is an object (a reference). And if your application uses other exception objects too, you additionally need to check whether this is an APR::Error object specifically. So most of the time, this is enough:

eval { $obj->mp_method() };
if ($@ && $ref $@ && $@ == $some_code)
    warn "handled exception: $@";
}

But with other, non-mod_perl, exception objects you need to do:

eval { $obj->mp_method() };
if ($@ && $ref $@ eq 'APR::Error' && $@ == $some_code)
    warn "handled exception: $@";
}

In theory you could even do:

eval { $obj->mp_method() };
if ($@ && $@ == $some_code)
    warn "handled exception: $@";
}

…but it's possible that the method will die with a plain string and not an object, in which case $@ == $some_code won't quite work. Remember that mod_perl throws exception objects only when Apache and APR fail, and in a few other special cases of its own (like exit). 🫠

warn "handled exception: $@" if $@ && $ref $@;

There are two ways to figure out whether an error fits your case. In most cases you just compare $@ with an the error constant. For example, if a socket has a timeout set and the data wasn't read within the timeout limit, you get an APR::Const::TIMEUP:

use APR::Const -compile => qw(TIMEUP);
$sock->timeout_set(1_000_000); # 1 sec
my $buff;
eval { $sock->recv($buff, BUFF_LEN) };
if ($@ && ref $@ && $@ == APR::Const::TIMEUP) {

}

However, there are situations where on different Operating Systems a different error code will be returned. In which case, to simplify the code, you should use the special subroutines provided by the APR::Status class. One such condition is socket recv() timeout, which on Unix throws the EAGAIN error, but on other systems it throws a different error. In this case, APR::Status::is_EAGAIN should be used. 🌈

Let's look at a complete example, bestie. Here's code that performs a socket read:

my $rlen = $sock->recv(my $buff, 1024);
warn "read $rlen bytes\n";

And in certain cases it times out. The code will die and log the reason for the failure, which is fine β€” but later on you may decide that you want to have another attempt to read before dying, and add some fine grained sleep time between attempts. Which can be achieved with select. Which gives us:

use APR::Status ();
# ....
my $tries = 0;
my $buffer;
RETRY: my $rlen = eval { $sock->recv($buffer, SIZE) };
if ($@)
    die $@ unless ref $@ && APR::Status::is_EAGAIN($@);
    if ($tries++ < 3) {
        # sleep 250msec
        select undef, undef, undef, 0.25;
        goto RETRY;
    }
    else {
        # do something else
    }
}
warn "read $rlen bytes\n"

Notice that we handle non-object and non-APR::Error exceptions as well, by simply re-throwing them. Bestie behaviour honestly. πŸ’–

Finally β€” the class is called APR::Error because it needs to be used outside mod_perl too, when called from APR applications written in Perl. She's flexible like that. πŸ’…


πŸ‘‘ API πŸ‘‘

πŸ’œ cluck

cluck is an equivalent of Carp::cluck that works with APR::Error exception objects.

πŸ’œ confess

confess is an equivalent of Carp::confess that works with APR::Error exception objects.

πŸ’œ strerror

Convert APR error code to its string representation.

$error_str = APR::Error::strerror($rc);
  • ret: $rc (APR::Const status constant) β€” the numerical value for the return (error) code. πŸ”’
  • ret: $error_str (string) β€” the string error message corresponding to the numerical value inside $rc. (Similar to the C function strerror(3)) πŸ’¬

since: 2.0.00

🌟 Example:

Try to retrieve the bucket brigade, and if the return value doesn't indicate success or end of file (usually in protocol handlers) die β€” but give the user the human-readable version of the error and not just the code. πŸŽ€

my $rc = $c->input_filters->get_brigade($bb_in,
                                        Apache2::Const::MODE_GETLINE);
if ($rc != APR::Const::SUCCESS && $rc != APR::Const::EOF) {
    my $error = APR::Error::strerror($rc);
    die "get_brigade error: $rc: $error\n";
}

It's probably a good idea not to omit the numerical value in the error message, in case the error string is generated with a non-English locale. Lowkey important. πŸ™ˆ


πŸ¦‹ SEE ALSO πŸ¦‹

mod_perl 2.0 documentation.


mod_perl 2.0 and its core modules are copyrighted under The Apache Software License, Version 2.0.


🫢 AUTHORS 🫢

The mod_perl development team and numerous contributors.


And that's the whole vibe, bestie β€” this was libapa...:Error(3pm) from perl v5.42.3, dated 2026-08-20. Go forth and handle your exceptions, you absolute icon. πŸ’–βœ¨πŸŽ€

πŸ“¦ where this page comes from