Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

andreasb's avatar

Guzzle Error Message gets truncated

Good evening,

sometimes I get an error message while calling on an API using Guzzle.

What drives me crraaaaaazzzyyy is the fact that the important part of the error message gets truncated! For Example:

exception 'GuzzleHttp\Exception\ClientException' with message 'Client error: `POST https://mws.amazonservices.de/[blablabla]` resulted in a `403 Forbidden` response:
<?xml version="1.0"?>
<ErrorResponse xmlns="http://mws.amazonaws.com/FulfillmentInboundShipment/2010-10-01/">
  <Error>
 (truncated...)
' in ....

I quickly found out about log_errors_max_len in my php.ini which I changed to 400, 99999 and even 0 - saved the file - restarted apache - phpinfo() confirms that the setting takes effect....BUT the message is still truncated!

I also deactivated all zend extensions to the best of my knowledge.

I even changed the Exception which is thrown to

 } catch (\Exception $e) {

and I tried the same via console - all to no avail.

What am I missing? This freaks me out a bit because without the error message it is really hard to see what to fix :-)

Thanks Andreas

0 likes
22 replies
joedawson's avatar

Try using the getBody() method on the response.

dd($response->getBody());
1 like
andreasb's avatar

Thanks for your reply @JoeDawson ! However, I can't because, the exception is thrown.

I do it like this

 $response = $client->post($this->url, [myparameters]

Which throws the exception, so in

 $response = $client->post($this->url, [myparameters]
dd($response->getBody());

the dd part is never executed.

Or am I thinking not correct here?

joedawson's avatar

Sorry, you'll need a try catch I guess. You could try this:

try {
    $response = $client->post($this->url, $params);
} catch(Exception $e) {
    dd($e->getBody());
}

You may need to replace the caught exception with the one Guzzle throws if it differs from the above.

1 like
andreasb's avatar

I am using a try/catch already - but strange, for both Exception and the \GuzzleHttp\Exception\ClientException there is no getBody() method.

I have setup XDebug now and I am debugging the Guzzle call step by step, lets see if that helps!

andreasb's avatar

I found the error - I changed some variables from env() to config() (according to 5.2 upgrade notes) and for whatever reason one setting didnt quite workout, turned out to be NULL and this was it. I would have never found out without XDebug - I like it now, really! :D

Thanks for your help @JoeDawson anyway :)

Good night Andreas

andreasb's avatar

Well, after I fixed this, of course the next error happend with this bloody amazon API and the error messages where truncated again.

After debugging for a while I finally found a way how to get the whole XML error message from the API:

            } catch (\GuzzleHttp\Exception\ClientException $e) {

                ddd($e->getResponse()->getBody()->getContents());

            }

The trick was to get the Response Object first, then via the getContents method you can access the stream with the whole XML in it.

Heureka!

64 likes
jabjol's avatar

Thanks for that andreasb. Was having the same problem with a simple mailchimp integration - error messages being truncated. That worked a treat.

2 likes
PlayIt's avatar

You can also set the 'http_errors' request option to false in Guzzle to skip the Try / Catch altogether.

4 likes
rip057's avatar

Not so much of an answer, but a hint because I had the same problem, until I realized there was several more piles of errors on top of the one that is all pretty printed in HTML and last in the list in the text login file on the server. Just look directly above the last error in the log file and so on and so forth. I had about 4.

nodenacci's avatar

I solved the problem by catching BadResponseException instead of ClientException with the same logic and it worked perfect. BadResponseException is the superclass for Guzzle exceptions

2 likes
sidk2020's avatar

I did something very adventurous. I modified guzzel's exception handler

guzzel on purpose only reads up 120 bytes of info and prints truncated next to it.

The file is located at : /vendor/guzzlehttp/guzzle/src/Exception/RequestException.php

So I modified that function and below is what my function looks like:

public static function getResponseBodySummary(ResponseInterface $response) { $body = $response->getBody();

    if (!$body->isSeekable() || !$body->isReadable()) {
        return null;
    }

    $size = $body->getSize();

    if ($size === 0) {
        return null;
    }

    // Matches any printable character, including unicode characters:
    // letters, marks, numbers, punctuation, spacing, and separators.
    if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/', $body)) {
        return null;
    }

    return $body;
    
}
S3C_MM's avatar

The following is a temporary solution. It will work until your next composer update or similar.

For guzzlehttp/psr7 before v2.0.

  1. Go to vendor/guzzlehttp/psr7/src/functions.php.
  2. Find function get_message_body_summary.
  3. Change the default value from $truncateAt = 120 to $truncateAt = 999999.

For guzzlehttp/psr7 v2.0 and later.

  1. Go to vendor/guzzlehttp/guzzle/src/Message.php.
  2. Find static function bodySummary.
  3. Change the default value from $truncateAt = 120 to $truncateAt = 999999.
S3C_MM's avatar

A bit more permanent solution.

app/Support/VendorFixes.php

<?php

declare(strict_types=1);

namespace App\Support;

use GuzzleHttp\Psr7\Message;

class VendorFixes
{
    public static function untruncateGuzzleMessages()
    {
        $reflector = new \ReflectionClass(Message::class);
        $path = $reflector->getFileName();
        $contents = file_get_contents($path);
        $contents = preg_replace(
            '/public static function bodySummary\(MessageInterface $message, int $truncateAt = 120\): \?string/',
            'public static function bodySummary(MessageInterface $message, int $truncateAt = 999999): ?string',
            $contents
        );
        file_put_contents($path, $contents);
    }
}

composer.json

{
    ...,
    "scripts": {
        "post-install-cmd": [
            "App\Support\VendorFixes::untruncateGuzzleMessages"
        ],
        "post-update-cmd": [
            "App\Support\VendorFixes::untruncateGuzzleMessages"
        ],
        ...
    }
}
S3C_MM's avatar

Just found an even better solution. One where you need not change vendor files.

Add the following to AppServiceProvider.php:

use GuzzleHttp\BodySummarizer;
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;

...
    public function register()
    {
        $this->app->bind(\GuzzleHttp\Client::class, function (Application $app, array $parameters = []) {
            $stack = \GuzzleHttp\HandlerStack::create();
            $stack->push(\GuzzleHttp\Middleware::httpErrors(new \GuzzleHttp\BodySummarizer(999999)), 'http_errors');
            return new \GuzzleHttp\Client(array_merge(['handler' => $stack], $parameters));
        });

        // If you bind or "singleton" any services, custom clients, etc. that depend on Client, use "$this->app->make(Client::class, ['anything but "handler"' => 'value']
    }
...
2 likes
quadroval's avatar

@S3C_MM Thanks for your solution! It really works, And now I can use it like:

app(\GuzzleHttp\Client::class, $config);

Though I added one more enhancement, I added removal of the standard 'http_errors' middleware

...
$stack->remove('http_errors'); // new line

$stack->push(\GuzzleHttp\Middleware::httpErrors(new \GuzzleHttp\BodySummarizer(999999)), 'http_errors');
...
1 like

Please or to participate in this conversation.