guzzle/promises · error · LogicException

should never be serialized

Error message

 should never be serialized

What it means

Classes using the internal NonSerializableTrait throw from __serialize() to block native PHP serialization. Promises and related objects hold live state (wait callbacks, closures, references to tasks/queues) that cannot survive serialize(), so the library fails fast instead of producing a broken, silently truncated object after unserialize(). static::class is interpolated into the message, naming the offending class.

Solutions

  1. Do not serialize promise objects; store only plain data (the awaited value or rejection reason) and rebuild the promise after retrieval.
  2. Call ->wait() to extract the concrete value before persisting, then wrap it in a new FulfilledPromise on the other side.
  3. Exclude promise objects from serialized payloads (unset them or use a whitelisting serializer).
  4. Log plain values, not promise instances.

Example fix

// before
$_SESSION['result'] = $promise; // serialize() later throws LogicException
// after
$_SESSION['result'] = $promise->wait(); // plain value
$promise = new \GuzzleHttp\Promise\FulfilledPromise($_SESSION['result']);
Defensive patterns

Strategy: try-catch

Validate before calling

if ($stateful instanceof \GuzzleHttp\Promise\PromiseInterface) {
    throw new \LogicException('Refusing to serialize a promise; persist ->wait() value instead.');
}

Type guard

function assertSerializable($value): void
{
    if (is_object($value) && ($value instanceof \GuzzleHttp\Promise\PromiseInterface)) {
        throw new \LogicException('Promises must not be serialized.');
    }
}

Try / catch

try {
    $blob = serialize($obj);
} catch (\LogicException $e) {
    $blob = serialize($obj->wait()); // persist the plain value instead
}

Prevention

When it happens

Trigger: Calling serialize($obj), or triggering indirect serialization via $_SESSION, var_export-less caches, APCu/Redis stores, igbinary, job queues, or error logs that serialize context, on an object of a class using NonSerializableTrait (promises, EachPromise, etc.).

Common situations: Storing pending promises in a PHP session between requests; caching promise objects in Redis/Memcached; pushing promises onto queue payloads; serializing exception traces that embed promises.

Related errors


AI-assisted analysis of guzzle/promises@42118e66a5 (2026-09-14). Data as JSON: /api/errors/04f793e4f08d1aeb. Report an issue: GitHub.

Appendix: source

Thrown at src/NonSerializableTrait.php:14

<?php

declare(strict_types=1);

namespace GuzzleHttp\Promise;

/**
 * @internal
 */
trait NonSerializableTrait
{
    public function __serialize(): array
    {
        throw new \LogicException(static::class.' should never be serialized');
    }

    public function __unserialize(array $data): void
    {
        throw new \LogicException(static::class.' should never be unserialized');
    }
}

View on GitHub (pinned to 42118e66a5)