NAME

API::Docker::Error::Stream - Failure reported inside a Docker Engine progress stream

VERSION

version 0.003

SYNOPSIS

my $events = eval { $docker->images->build(context => $tar, t => 'app:v1') };
if (my $err = $@) {
    # Behaves exactly like the string it replaces ...
    warn "build failed: $err";

    # ... and carries the whole stream that led up to the failure.
    if (ref $err && $err->isa('API::Docker::Error::Stream')) {
        for my $event (@{ $err->events }) {
            print $event->{stream} if defined $event->{stream};
        }
    }
}

DESCRIPTION

The engine's streaming endpoints -- /build, /images/create (pull) and /images/{name}/push -- report a failed operation as an errorDetail object inside a stream that was already answered with HTTP 200. A client that only treats status >= 400 as an error hands a broken build back to its caller as a success.

API::Docker::Role::HTTP therefore croaks with an object of this class as soon as an errorDetail event appears in such a stream. The object exists purely so the progress output is not lost with the failure: the complete event list, error event included, is available through "events".

It is still the string it replaces

Everything else in this distribution croaks plain strings, and callers rely on that. This class overloads stringification (with fallback => 1, so comparison, concatenation, sprintf and matching all work through it) and produces exactly what croak would have died with: the reason, followed by Carp's own at FILE line N. location suffix. Code written against the old behaviour keeps working unchanged:

eval { $docker->images->build(...) };
if ($@) {
    (my $reason = $@) =~ s/\s+at\s+\S+\s+line\s+\d+\.?//g;   # still works
    die "no good: $@";                                        # still works
    warn $@ if $@ =~ /exit status/;                           # still works
}

Note that a substitution on $@ replaces the object in that scalar with a plain string, as it would with any overloaded object, so take a copy first if "events" is still wanted afterwards.

The boolean overload is explicit rather than derived from the string, so an engine message of 0 cannot make a live exception test false.

message

The reason on its own, without the location suffix: the errorDetail.message the engine sent, prefixed with the request it belongs to. Trailing whitespace is stripped -- engine messages usually end in a newline, and Carp appends no location to a message that already ends in one.

events

ArrayRef of every event decoded from the stream, in order, the errorDetail event included. This is the progress output the caller would otherwise lose by never receiving a return value.

location

Carp's location suffix ( at FILE line N.\n), captured at the point the error was raised so it names the same frame a plain croak would have named. Kept apart from "message" so a caller can have the reason without it.

as_string

my $text = $err->as_string;   # same as "$err"

The message and the location suffix, concatenated. This is what the stringification overload returns.

SEE ALSO

SUPPORT

Issues

Please report bugs and feature requests on GitHub at https://github.com/Getty/p5-api-docker/issues.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHOR

Torsten Raudssus <getty@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.