Skip to content
This repository has been archived by the owner on Jan 6, 2024. It is now read-only.

Exceptions thrown in chained promises are wrapped #47

Open
thewilkybarkid opened this issue Nov 27, 2017 · 4 comments
Open

Exceptions thrown in chained promises are wrapped #47

thewilkybarkid opened this issue Nov 27, 2017 · 4 comments

Comments

@thewilkybarkid
Copy link

Q A
Bug? yes
New Feature? no
Version v1.1.1

Actual Behavior

When chaining a promise and throwing an exception, the exception is wrapped inside an Exception with the message Invalid exception returned from Guzzle6.

Expected Behavior

That my exception is thrown directly.

Steps to Reproduce

$httpClient->sendAsyncRequest(new Request('GET', 'https://www.example.com/'))
    ->then(function (ResponseInterface $response) {
        throw new \Exception('Some problem');
    })
    ->wait();

... results in a RuntimeException with the message Invalid exception returned from Guzzle6 (with my Exception as previous).

Possible Solutions

The exception wrapping only makes sense when the actual request is being made (anything beyond that is not Guzzle). Either then return a different promise type in Promise::then()

return new static($this->promise->then($onFulfilled, $onRejected), $this->request);
or stop catching any exception
} elseif ($reason instanceof \Exception) {
$this->exception = new \RuntimeException('Invalid exception returned from Guzzle6', 0, $reason);
} else {
$this->exception = new \UnexpectedValueException('Reason returned from Guzzle6 must be an Exception', 0, $reason);
}

(Related, this will also hide any fatal errors (eg TypeError) behind the meaningless 'Reason returned from Guzzle6 must be an Exception' exception.)

@Nyholm
Copy link
Member

Nyholm commented Sep 9, 2018

@joelwurtz Can I get your opinion on this?

@joelwurtz
Copy link
Member

That's because we only allow HttpException / ResponseInterface in our promise chain, if you want to deal with others types you have to return your own promise implementation (or an existing one) that does not limit you to those types.

However there is indeed some errors, (like relying on \Exception instead of \Throwable), and also we should return HttpException (and not \RuntimeException | \UnexpectedValueException)

@thewilkybarkid
Copy link
Author

Not according to https://github.com/php-http/promise/blob/1cc44dc01402d407fc6da922591deebe4659826f/src/Promise.php#L64-L66.

I don't understand the reasoning for limiting the type. You're suggesting turning it back into a Guzzle (or whatever) promise?

@murilozilli
Copy link

murilozilli commented May 25, 2021

Has this moved forward at all? Having issues with request exceptions on promises not being rejected and not being catched by catch (RequestException $re), I am not sure this is why.

#0 /app/vendor/guzzlehttp/guzzle/src/Middleware.php(66): GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Psr7\Response))
#1 /app/vendor/guzzlehttp/promises/src/Promise.php(203): GuzzleHttp\Middleware::GuzzleHttp\{closure}(Object(GuzzleHttp\Psr7\Response))
#2 /app/vendor/guzzlehttp/promises/src/Promise.php(156): GuzzleHttp\Promise\Promise::callHandler(1, Object(GuzzleHttp\Psr7\Response), Array)
#3 /app/vendor/guzzlehttp/promises/src/TaskQueue.php(47): GuzzleHttp\Promise\Promise::GuzzleHttp\Promise\{closure}()
#4 /app/vendor/guzzlehttp/promises/src/Promise.php(246): GuzzleHttp\Promise\TaskQueue->run(true)
#5 /app/vendor/guzzlehttp/promises/src/Promise.php(223): GuzzleHttp\Promise\Promise->invokeWaitFn()
#6 /app/vendor/guzzlehttp/promises/src/Promise.php(267): GuzzleHttp\Promise\Promise->waitIfPending()
#7 /app/vendor/guzzlehttp/promises/src/Promise.php(225): GuzzleHttp\Promise\Promise->invokeWaitList()
#8 /app/vendor/guzzlehttp/promises/src/Promise.php(62): GuzzleHttp\Promise\Promise->waitIfPending()
#9 /app/vendor/guzzlehttp/guzzle/src/Client.php(131): GuzzleHttp\Promise\Promise->wait()
#10 /app/vendor/guzzlehttp/guzzle/src/Client.php(89): GuzzleHttp\Client->request('get', 'someurl/123', Array)

Line 203 of the promise(Stack trace #1) is $promise->resolve($handler[$index]($value));:

            if (isset($handler[$index])) {
                $promise->resolve($handler[$index]($value));
            } elseif ($index === 1) {
                // Forward resolution values as-is.
                $promise->resolve($value);
            } else {
                // Forward rejections down the chain.
                $promise->reject($value);
            }

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants