{"record":{"id":"d9c1620cf3258b89","repo":"guzzle/promises","slug":"should-never-be-unserialized","errorCode":null,"errorMessage":" should never be unserialized","messagePattern":" should never be unserialized","errorType":"exception","errorClass":"LogicException","httpStatus":null,"severity":"error","filePath":"src/NonSerializableTrait.php","lineNumber":19,"sourceCode":"<?php\n\ndeclare(strict_types=1);\n\nnamespace GuzzleHttp\\Promise;\n\n/**\n * @internal\n */\ntrait NonSerializableTrait\n{\n    public function __serialize(): array\n    {\n        throw new \\LogicException(static::class.' should never be serialized');\n    }\n\n    public function __unserialize(array $data): void\n    {\n        throw new \\LogicException(static::class.' should never be unserialized');\n    }\n}\n","sourceCodeStart":1,"sourceCodeEnd":22,"githubUrl":"https://github.com/guzzle/promises/blob/42118e66a53c492effaf92bc357e931985d5c6f9/src/NonSerializableTrait.php#L1-L22","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Purge/regenerate caches and sessions that contain serialized promise objects.","Change persisted format to plain data; reconstruct promises explicitly after unserialize().","Use unserialize() allowed_classes options (or similar) to keep promise classes out of untrusted payloads.","Audit serialization call sites for promise-typed values."],"exampleFix":"// before\n$promise = unserialize($cached); // LogicException\n// after\n$value = unserialize($cached); // plain value\n$promise = new \\GuzzleHttp\\Promise\\FulfilledPromise($value);","handlingStrategy":"try-catch","validationCode":"// Detect non-restorable payloads before unserialize():\nif (preg_match('/O:\\d+:\"[^\"]*(Promise|EachPromise)[^\"]*\"/', $blob) === 1) {\n    throw new \\LogicException('Payload contains promise objects; discard or migrate it.');\n}","typeGuard":null,"tryCatchPattern":"try {\n    $value = unserialize($blob, ['allowed_classes' => false]);\n} catch (\\LogicException $e) {\n    $value = null; // rebuild state from plain data / invalidate cache entry\n}","preventionTips":["Persist plain data, not promise objects, so payloads stay unserialize-able across upgrades.","Invalidate old caches when upgrading a library that adds serialization guards.","Use allowed_classes options when unserializing untrusted data."],"tags":["serialization","unserialize","promises","guzzle"],"backgroundTag":"object-not-serializable","analyzedSha":"42118e66a53c492effaf92bc357e931985d5c6f9","analyzedAt":"2026-09-14T00:10:14.865Z","contentChangedAt":"2026-09-14T00:10:14.865Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}