```{index} single: error handling, single: I/O; errors, single: $! ``` # Handling errors Every I/O operation can fail. The filesystem can be full, the permissions can be wrong, the file can be missing, the network mount can vanish mid-read. Perl does not raise exceptions for these by default — it returns a false value and sets `$!`. The programmer's job is to notice. ```{index} single: die, single: or die idiom, single: operator precedence; or vs ||, single: $@ ``` ## The `or die` idiom ```perl open my $fh, "<", $path or die "open $path: $!"; ``` The form has three loadbearing parts: - **`or`**, not `||`. Precedence matters: `open(...) || die` would group the `||` against the full argument list of `open`. Using `or` binds lowest of all the operators involved and always does what it reads as. - **The filename in the message.** `"$!"` alone says "Permission denied" with no context. `"open $path: $!"` says what file, in what step. When logs are all you have, context is everything. - **`$!`, not `$@`**. `$!` is the system error — `errno` with a human-readable face. `$@` is the exception from the most recent `eval`. Mixing them up at 3am has happened to everyone. Every `open`, every `close`, every `print`, every `read`, every `binmode` in production code has a check. There is no "it obviously cannot fail here". The one time it does, you will want the diagnostic. ```{index} single: $!; volatility, single: errno ``` ## Read `$!` immediately or not at all `$!` reflects the **most recent** system call. A naive sequence: ```perl open my $fh, "<", $path; my $line = <$fh>; # might also set $! warn "something failed: $!" unless $line; ``` If the `open` failed, `$!` is already overwritten by the time `<$fh>` runs on the undefined handle. Check the return value of each call right where you call it. ```{index} single: close; error checking, single: $? ``` ## Pattern: check the `close` as carefully as the `open` ```perl open my $fh, ">", $path or die "open $path: $!"; print $fh @records or die "write $path: $!"; close $fh or die "close $path: $!"; ``` On a write handle, `close` is where the kernel actually commits the buffered data. If the disk is full, `print` may have succeeded into memory and `close` is where you find out. The close check is not a stylistic flourish; it is the one that catches the half-written log entry. For pipes, `close` additionally waits for the child and sets `$?`. See [Pipes](pipes) for the diagnostic wrapper that decomposes `$?` into signal and exit-status components. ```{index} single: autodie, single: exceptions, pair: autodie; lexical scope ``` ## `autodie` — errors become exceptions For code where every line is a `... or die ...` chain, the `autodie` pragma is worth the import: ```perl use autodie qw(:all); open my $fh, "<", $path; while (my $line = <$fh>) { # ... } close $fh; ``` With `autodie`, built-ins like `open`, `close`, `print`, `read`, `chdir`, `unlink`, and a long list of siblings throw a structured exception on failure instead of returning false. The caller catches them with `eval { ... }` or a block-form `try`, and the message names the call and the path automatically. Two practical notes: - `autodie` is **lexical**. It applies only inside the block where it is `use`-d. A module you call from an `autodie` block does not pick up the pragma. - `autodie` does not change the return convention for the **success** case. `open` still returns a true value; `$fh` is still the handle. You can delete your `or die` suffixes and everything else keeps working. ```{index} single: eval; exception catching, single: die; trailing newline, single: exception objects ``` ## What the Perl exception looks like Whether you `die` manually or let `autodie` do it, the exception travels up the stack until something catches it. Catching is `eval` plus a check of `$@`: ```perl my $fh = eval { open my $h, "<", $path or die "open $path: $!\n"; $h; }; if ($@) { warn "could not read $path: $@"; # ... fall back to a default, or return an error, or re-die ... } ``` Two habits that save time: - **Terminate die strings with `\n` when you want the raw message.** Without a trailing newline, Perl appends `" at FILE line N"` to the `die` string. Sometimes that is what you want; often it is noise. - **Prefer structured objects for non-trivial errors.** A `bless { path => ..., errno => $!, step => "open" }, 'IOError'` costs three lines and gives the caller something to introspect instead of a string to regex. ```{index} single: error handling; checklist ``` ## A minimal checklist Every open-and-process block should look, structurally, like this: ```perl open my $fh, MODE, $path or die "open $path: $!"; binmode $fh, $layer or die "binmode $path: $!" if $layer_not_already_in_mode; # ... do I/O; each op checked in-place ... close $fh or die "close $path: $!"; ``` If the code deviates — a missing check, a `||` where an `or` belongs, a `$@` where `$!` belongs — that is where the bug is hiding. ## Where to go next This chapter covered the everyday `open`. When you need flag-level control over the system call itself — for example, `O_EXCL` to refuse to clobber, or `O_NONBLOCK` for a pipe you intend to `select` on — reach for [`sysopen`](../../p5/core/perlfunc/sysopen) and its unbuffered companions [`sysread`](../../p5/core/perlfunc/sysread) and [`syswrite`](../../p5/core/perlfunc/syswrite).