briannesbitt/Carbon · error · InvalidFormatException

Invalid serialized value: $value

Error message

Invalid serialized value: $value

What it means

fromSerialized() runs PHP unserialize() (error-suppressed) on the payload and requires the result to be an instance of the class it was called on. If unserialize() returns false, triggers a fatal, is blocked by the allowed_classes option, or yields a different class (e.g. a Carbon stored but fromSerialized called on CarbonImmutable), Carbon throws InvalidFormatException. It exists as the single decoding gate for data produced by serialize($date).

Source

Thrown at src/Carbon/Traits/Serialization.php:96

     *
     * @example
     * ```php
     * $object = Carbon::fromSerialized($value, ['allowed_classes' => [Carbon::class, CarbonImmutable::class]]);
     * ```
     *
     * @param \Stringable|string $value
     * @param array              $options example: ['allowed_classes' => [CarbonImmutable::class]]
     *
     * @throws InvalidFormatException
     *
     * @return static
     */
    public static function fromSerialized($value, array $options = []): static
    {
        $instance = @unserialize((string) $value, $options);

        if (!$instance instanceof static) {
            throw new InvalidFormatException("Invalid serialized value: $value");
        }

        return $instance;
    }

    /**
     * The __set_state handler.
     *
     * @param string|array $dump
     *
     * @return static
     */
    #[ReturnTypeWillChange]
    public static function __set_state($dump): static
    {
        if (\is_string($dump)) {
            return static::parse($dump);
        }

View on GitHub (pinned to b13f05955d)

Solutions

  1. Stop storing PHP-serialized objects: write ->toISOString() (or format('Y-m-d H:i:s.u e O')) and read back with Carbon::parse() - ISO strings survive upgrades and cross-language use
  2. Flush/regenerate the stale serialized cache entries after upgrading Carbon or renaming classes
  3. Verify you are calling fromSerialized on the exact class (or a parent) that was serialized, and that allowed_classes includes it
  4. Catch InvalidFormatException and rebuild the date from a canonical fallback (e.g. created_at column or 'now') while logging the bad payload

Example fix

// before
$cache->put('since', serialize($startDate));
$since = Carbon::fromSerialized($cache->get('since'));

// after
$cache->put('since', $startDate->toISOString());
$since = Carbon::parse($cache->get('since'));
Defensive patterns

Strategy: try-catch

Validate before calling

// Cheap sanity check before unserialize: serialized Carbon starts with 'O:' or 'C:'
if (!is_string($payload) || !preg_match('/^[OC]:\d+:/', $payload)) {
    throw new InvalidArgumentException('Not a PHP-serialized object payload');
}

Type guard

function looksSerializedObject(mixed $value): bool
{
    return is_string($value) && preg_match('/^[OC]:\d+:["\\]/', $value) === 1;
}

Try / catch

use Carbon\Exceptions\InvalidFormatException;

try {
    $since = Carbon::fromSerialized($cached);
} catch (InvalidFormatException $e) {
    $since = Carbon::parse($row['created_at']); // canonical fallback
    $cache->put('since', $since->toISOString());  // heal the entry
}

Prevention

When it happens

Trigger: Unserialize a Carbon payload written by an older Carbon major version (class layout/renames make the payload invalid); calling Carbon::fromSerialized(json_encode($date)) with JSON instead of PHP serialize format; passing a truncated/corrupted blob from cache or DB; options ['allowed_classes' => [...]] that omit the target class; storing a Carbon instance but reading it back via a subclass that does not extend it.

Common situations: Serialized Carbon objects in Redis/session/queue payloads that break after a Carbon 2-to-3 upgrade or a project namespace move; cache entries not invalidated after deploy; mixing serialization formats (JSON on write, fromSerialized on read); security-hardened unserialize settings that disable class loading.

Related errors


AI-assisted analysis of briannesbitt/Carbon@b13f05955d (2026-08-17). Data as JSON: /api/errors/443d460fb1fd9e2c. Report an issue: GitHub.