guzzle/promises · error · LogicException

should never be unserialized

Error message

 should never be unserialized

What it means

This is the unserialize-side twin of the serialization guard: __unserialize() on any class using NonSerializableTrait throws immediately, so an object of that class can never be restored from a serialized payload. This exists so that even a payload crafted directly (bypassing __serialize) cannot resurrect a promise with dead callbacks and broken internal state.

Solutions

  1. Purge/regenerate caches and sessions that contain serialized promise objects.
  2. Change persisted format to plain data; reconstruct promises explicitly after unserialize().
  3. Use unserialize() allowed_classes options (or similar) to keep promise classes out of untrusted payloads.
  4. Audit serialization call sites for promise-typed values.

Example fix

// before
$promise = unserialize($cached); // LogicException
// after
$value = unserialize($cached); // plain value
$promise = new \GuzzleHttp\Promise\FulfilledPromise($value);
Defensive patterns

Strategy: try-catch

Validate before calling

// Detect non-restorable payloads before unserialize():
if (preg_match('/O:\d+:"[^"]*(Promise|EachPromise)[^"]*"/', $blob) === 1) {
    throw new \LogicException('Payload contains promise objects; discard or migrate it.');
}

Try / catch

try {
    $value = unserialize($blob, ['allowed_classes' => false]);
} catch (\LogicException $e) {
    $value = null; // rebuild state from plain data / invalidate cache entry
}

Prevention

When it happens

Trigger: Calling unserialize() on a payload representing a class using NonSerializableTrait (e.g. data cached before upgrading, payloads from another system, or attacker-supplied strings naming promise classes), or unserializing data that embeds a promise object.

Common situations: Restoring old cache entries that predate the guard; unserialize() of session data after the library started using the trait; deserializing queued jobs that accidentally embedded promises.

Related errors


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

Appendix: source

Thrown at src/NonSerializableTrait.php:19

<?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)