Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unsupported operand types #2016

Closed
codeinuit opened this issue Feb 23, 2018 · 27 comments
Closed

Unsupported operand types #2016

codeinuit opened this issue Feb 23, 2018 · 27 comments

Comments

@codeinuit
Copy link

Hello,
I'm actually trying to use Auth0 integration on a Prestashop module, but after installed the integration with Composer, i've this error :

[PrestaShop] Fatal error in module file: /var/www/html/modules/prestashop/vendor/guzzlehttp/guzzle/src/Client.php:236
Unsupported operand types

Is that a bug ? It's actually stucking me.
Thanks in advance.

Lucas

@sagikazarmark
Copy link
Member

What is your Guzzle version? What is your PHP version?

A bit more detailed stack trace would be nice, because without that you won't be able to find the usage of the library and without input parameters we cannot reproduce the issue.

Looking at the latest code on the aformentioned line there is an array merging operation which awaits two arrays. Maybe there is an uncompatible input there.

@codeinuit
Copy link
Author

codeinuit commented Feb 23, 2018

I'm sorry, it's actually the first time i'm asking help here for something.
My PHP version is 7.1.14 (running on a Docker), and it's actually installed with Auth0 package (Composer) so i don't have the version but i guess it should be the last one..

About the logs, it's all i got.
I just downloaded it with Composer and i got this error :<

@sagikazarmark
Copy link
Member

I'm sorry, it's actually the first time i'm asking help here for something.

No problem, just a friendly reminder. ;)

(Composer) so i don't have the version but i guess it should be the last one..

You can check the version in the composer.lock file

@codeinuit
Copy link
Author

I'll keep that in my mind for the future, thanks :)

I'm using guzzlehttp 6.3.0

@sagikazarmark
Copy link
Member

Without the actual stack trace it's going to be hard to identify the problem. Can you debug the code?

If you have no debugging tools at hand, at least could you go to that line and var_dump the two operands (poor mans debug)?

@codeinuit
Copy link
Author

codeinuit commented Feb 23, 2018

I've only the code of the guzzle library on my folder. The only line of code i've called is
"require_once(dirname(FILE) . '/vendor/autoload.php');"

It concern the operand "$result = $options + $defaults;"

Here's the complete function affiliated :

 private function prepareDefaults($options)
    {
        $defaults = $this->config;

        if (!empty($defaults['headers'])) {
            // Default headers are only added if they are not present.
            $defaults['_conditional'] = $defaults['headers'];
            unset($defaults['headers']);
        }

        // Special handling for headers is required as they are added as
        // conditional headers and as headers passed to a request ctor.
        if (array_key_exists('headers', $options)) {
            // Allows default headers to be unset.
            if ($options['headers'] === null) {
                $defaults['_conditional'] = null;
                unset($options['headers']);
            } elseif (!is_array($options['headers'])) {
                throw new \InvalidArgumentException('headers must be an array');
            }
        }

        // Shallow merge defaults underneath options.
        $result = $options + $defaults;

        // Remove null values.
        foreach ($result as $k => $v) {
            if ($v === null) {
                unset($result[$k]);
            }
        }

        return $result;
    }

@sagikazarmark
Copy link
Member

Yup, that's it. This line in particular:

$result = $options + $defaults;

Can you dump those two variables before merging them?

@codeinuit
Copy link
Author

codeinuit commented Feb 24, 2018

Here's what i got.
The first (string) is the $options value, and the second one is $defaults.

string(38) "1var/www/html/app/cache/dev/cacert.pem"
array(9) { ["base_url"]=> string(33) "https://api-addons.prestashop.com" ["defaults"]=> array(1) { ["timeout"]=> string(3) "5.0" } ["handler"]=> object(GuzzleHttp\HandlerStack)#393 (3) { ["handler":"GuzzleHttp\HandlerStack":private]=> object(Closure)#446 (2) { ["static"]=> array(2) { ["default"]=> object(Closure)#416 (2) { ["static"]=> array(2) { ["default"]=> object(GuzzleHttp\Handler\CurlMultiHandler)#457 (5) { ["factory":"GuzzleHttp\Handler\CurlMultiHandler":private]=> object(GuzzleHttp\Handler\CurlFactory)#459 (2) { ["handles":"GuzzleHttp\Handler\CurlFactory":private]=> array(0) { } ["maxHandles":"GuzzleHttp\Handler\CurlFactory":private]=> int(50) } ["selectTimeout":"GuzzleHttp\Handler\CurlMultiHandler":private]=> int(1) ["active":"GuzzleHttp\Handler\CurlMultiHandler":private]=> NULL ["handles":"GuzzleHttp\Handler\CurlMultiHandler":private]=> array(0) { } ["delays":"GuzzleHttp\Handler\CurlMultiHandler":private]=> array(0) { } } ["sync"]=> object(GuzzleHttp\Handler\CurlHandler)#454 (1) { ["factory":"GuzzleHttp\Handler\CurlHandler":private]=> object(GuzzleHttp\Handler\CurlFactory)#389 (2) { ["handles":"GuzzleHttp\Handler\CurlFactory":private]=> array(0) { } ["maxHandles":"GuzzleHttp\Handler\CurlFactory":private]=> int(3) } } } ["parameter"]=> array(2) { ["$request"]=> string(10) "" ["$options"]=> string(10) "" } } ["streaming"]=> object(GuzzleHttp\Handler\StreamHandler)#394 (1) { ["lastHeaders":"GuzzleHttp\Handler\StreamHandler":private]=> array(0) { } } } ["parameter"]=> array(2) { ["$request"]=> string(10) "" ["$options"]=> string(10) "" } } ["stack":"GuzzleHttp\HandlerStack":private]=> array(4) { [0]=> array(2) { [0]=> object(Closure)#464 (1) { ["parameter"]=> array(1) { ["$handler"]=> string(10) "" } } [1]=> string(11) "http_errors" } [1]=> array(2) { [0]=> object(Closure)#469 (1) { ["parameter"]=> array(1) { ["$handler"]=> string(10) "" } } [1]=> string(15) "allow_redirects" } [2]=> array(2) { [0]=> object(Closure)#470 (1) { ["parameter"]=> array(1) { ["$handler"]=> string(10) "" } } [1]=> string(7) "cookies" } [3]=> array(2) { [0]=> object(Closure)#423 (1) { ["parameter"]=> array(1) { ["$handler"]=> string(10) "" } } [1]=> string(12) "prepare_body" } } ["cached":"GuzzleHttp\HandlerStack":private]=> NULL } ["allow_redirects"]=> array(5) { ["max"]=> int(5) ["protocols"]=> array(2) { [0]=> string(4) "http" [1]=> string(5) "https" } ["strict"]=> bool(false) ["referer"]=> bool(false) ["track_redirects"]=> bool(false) } ["http_errors"]=> bool(true) ["decode_content"]=> bool(true) ["verify"]=> bool(true) ["cookies"]=> bool(false) ["_conditional"]=> array(2) { ["Accept"]=> string(16) "application/json" ["User-Agent"]=> string(39) "GuzzleHttp/6.2.1 curl/7.38.0 PHP/5.6.33" } }

(Sorry for the late answer)

@sagikazarmark
Copy link
Member

Well, you will have to debug how that value reached the prepare method. It's provided by some external caller.

@murilohns
Copy link

Hello @P147x, did you solved that problem?

1 similar comment
@soldierm
Copy link

Hello @P147x, did you solved that problem?

@codeinuit
Copy link
Author

Hello guys, sorry for the last answer.
Its been a time, and i forgot a bit. I think the problem was the Auth0 integration who was currently using guzzle, maybe in a wrong way. Are you having a similar issue ?

@weinasi
Copy link

weinasi commented Mar 4, 2020

my $options value and $defaults value:
options:{"synchronous":true} defaults:{"handler":{},"base_uri":{},"allow_redirects":{"max":5,"protocols":["http","https"],"strict":false,"referer":false,"track_redirects":false},"http_errors":true,"decode_content":true,"verify":true,"cookies":false,"idn_conversion":true,"_conditional":{"User-Agent":"GuzzleHttp/6.5.1 curl/7.56.0 PHP/7.1.32"}}

@weinasi
Copy link

weinasi commented Mar 4, 2020

this is my trace:
[2020-03-04 00:45:17] test.ERROR: Unsupported operand types {"exception":"[object] (Symfony\Component\Debug\Exception\FatalThrowableError(code: 0): Unsupported operand types at /data/wwwroot/test_snow/vendor/guzzlehttp/guzzle/src/Client.php:320)
[stacktrace]
#0 /data/wwwroot/test_snow/vendor/guzzlehttp/guzzle/src/Client.php(149): GuzzleHttp\Client->prepareDefaults(Array)
#1 /data/wwwroot/test_snow/vendor/guzzlehttp/guzzle/src/Client.php(183): GuzzleHttp\Client->requestAsync('shouldReport', Array, Array)
#2 /data/wwwroot/test_snow/vendor/guzzlehttp/guzzle/src/Client.php(96): GuzzleHttp\Client->request('shouldReport', Array, Array)
#3 /data/wwwroot/test_snow/vendor/guzzlehttp/guzzle/src/Client.php(63): GuzzleHttp\Client->__call('shouldReport', Array)

@connor11528
Copy link

also having issue with Unsupported operand types. Looks like $options and $defaults are both array types, should we really be merging them with a +?

// Shallow merge defaults underneath options.
$result = $options + $defaults;

@mfn
Copy link

mfn commented Aug 28, 2020

should we really be merging them with a +?

This is perfectly fine and well documented at https://www.php.net/manual/en/language.operators.array.php

The + operator returns the right-hand array appended to the left-hand array; for keys that exist in both arrays, the elements from the left-hand array will be used, and the matching elements from the right-hand array will be ignored.

Or in plain english: it's the most common way to have a user-provided array and a defaults-array and produce a result where all the defaults missing in the user-provided are filled in. The method is poignantly called prepareDefaults for that reason.

Everyone having the problem: the problem is that something outside Guzzle passes data in where either operand is not an array anymore, as is evident by #2016 (comment)

@Nyholm
Copy link
Member

Nyholm commented Oct 10, 2020

Thank you @mfn

@Nyholm Nyholm closed this as completed Oct 10, 2020
@FrancoisPrigent
Copy link

FrancoisPrigent commented Oct 26, 2020

It happens when you don't call the Guzzle client construct method.

@carltondickson
Copy link

This is my stack trace for a similar issue with PHP7.4 and Guzzle 7.2.0

#42 /vendor/guzzlehttp/guzzle/src/Client.php(304): GuzzleHttp\Client::prepareDefaults
#41 /vendor/guzzlehttp/guzzle/src/Client.php(154): GuzzleHttp\Client::requestAsync
#40 /vendor/guzzlehttp/guzzle/src/Client.php(187): GuzzleHttp\Client::request
#39 /vendor/guzzlehttp/guzzle/src/Client.php(92): GuzzleHttp\Client::__call
#38 /vendor/guzzlehttp/guzzle/src/Client.php(57): GuzzleHttp\Client::__construct

and part of the code

            $http = new Client([
                'verify' => App::environment('local') ? false : true,
            ]);
            $response = $http->get($url, [
                'headers' => $headers,
                'query'   => $query,
            ]);

Noticed that when running this locally I end up in the get method inside of vendor/guzzlehttp/guzzle/src/ClientTrait.php method instead of the __call method where the problem merging options and defaults seems to trigger.

This piece of code runs as part of a job and the server also has New Relic extension installed on it...not sure if this is the problem but found this (https://discuss.newrelic.com/t/php-guzzle-errors-in-php-agent-9-0/91477/22)

I'm trying to figure out how this happens and will update this post if I can find out why.

@mfn
Copy link

mfn commented Mar 29, 2021

As to the reference with the newrelic forum, be careful, the last comment says:

from time to time it somehow breaks, which causes all guzzle related jobs to fail until the newrelic daemon is restarted

Which is a clear indicator it's unrelated to Guzzle.

/vendor/guzzlehttp/guzzle/src/Client.php(304)

This is exactly this line:

        $result = $options + $defaults;

Either $options or $defaults is not an array (anymore).

I suggest to temporarily add debugging code before this line to witness what those two values are and check it out once you hit problem again.

@carltondickson
Copy link

Running locally, my debugger stops in the get method as expected but on the remote server instead of calling get it tries to find this method via __call given the stack trace above.

Still digging, but what could cause Client to execute the magic method __call instead of the get method in vendor/guzzlehttp/guzzle/src/ClientTrait.php.

@mfn
Copy link

mfn commented Mar 29, 2021

but what could cause Client to execute the magic method __call instead of the get method

Oh, thanks for pointing this out again! You already mentioned it but I missed it. This is very strange.

What perplexes me, it looks like there something missing: how could it get there?

but on the remote server instead of calling get

Ah, that get method from the trait 😅 Man, this naming is confusing =>

public function get($uri, array $options = []): ResponseInterface

Is there a problem with code being not up2date, weird caching?

Looks like as if the ClientTrait is not applied? 🤔 Do your source versions match?

@carltondickson
Copy link

This error started occuring after upgrading a project from Laravel 5.x to 8 (Guzzle 6.5.5 to 7.2.0).
Will see if there is any sort of caching going on, it definitely feels like something is still trying to use some old code where this trait doesn't exist. We're running the project on Heroku so anything is possible once the code is running on one of their dynos.

The composer log on deploy shows this

- Installing guzzlehttp/guzzle (7.2.0): Extracting archive

Checked the vendor directory on the server and can see that this trait exists and looks correct in the sense that the get method is there

@sblawrie
Copy link

I'm also having this issue on Laravel 8, Guzzle 7.3. I use New Relic, so I think it's probably related to that.

@LasseRafn
Copy link

I'm seeing this after installing New Relic, never before. I suppose its new relic related

@fhferreira
Copy link

anyone solve it?

@GrahamCampbell
Copy link
Member

Upgrade to the latest version. You may need ton upgrade both local and global.

@guzzle guzzle locked as resolved and limited conversation to collaborators Dec 26, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests