phalcon/cphalcon · error · Phalcon\Storage\Serializer\Exceptions\InvalidUnserializationInput

Data for the unserializer must be of type string

Error message

Data for the unserializer must be of type string

What it means

Php::unserialize() first applies isSerializable(): null, booleans and numeric values are returned as-is without decoding. Whatever remains must be a serialize() string; a non-string that survives the filter — array, object, resource — throws InvalidUnserializationInput. unserialize() is meant to consume serialize() output, not already-decoded data.

Source

Thrown at phalcon/Storage/Serializer/Php.zep:48

        return this->phpSerialize(this->data);
    }

    /**
     * Unserializes data
     */
    public function unserialize(mixed data) -> void
    {
        var result;

        if (true !== this->isSerializable(data)) {
            let this->data = data;

            return;
        }

        if unlikely typeof data != "string" {
            throw new InvalidUnserializationInput();
        }

        globals_set("warning.enable", false);
        set_error_handler(
            function (number, message, file, line) {
                globals_set("warning.enable", true);
            },
            E_NOTICE | E_WARNING
        );

        let result = this->phpUnserialize(data);

        restore_error_handler();

        if unlikely globals_get("warning.enable") || result === false {
            let this->isSuccess = false,
                result          = "";
        } else {

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Call unserialize() only with strings produced by serialize()
  2. Check before decoding: if (is_string($data)) { $serializer->unserialize($data); } else { $value = $data; }
  3. Rely on the adapter's get() — it serializes/unserializes exactly once per round-trip
  4. When accepting payloads from other systems, detect the format (leading 'a:1:{' vs '{') instead of assuming

Example fix

// before
$serializer->unserialize($payload); // $payload already an array -> throws

// after
$value = is_string($payload) ? $serializer->unserialize($payload) && $serializer->getData() : $payload;
Defensive patterns

Strategy: type-guard

Validate before calling

if (is_string($payload)) {
    $serializer->unserialize($payload);
    $value = $serializer->getData();
} else {
    $value = $payload; // already decoded
}

Type guard

function isPhpSerializedString(mixed $data): bool
{
    return is_string($data) && preg_match('/^[aObsiNd]:\d+:/i', $data) === 1;
}

Prevention

When it happens

Trigger: Passing an already-unserialized array to Php::unserialize() (double decoding); feeding an object/resource payload; storage returning an array-shaped payload into the serializer; queue/job code unserializing a message that was json-decoded earlier in the pipeline.

Common situations: Manual serializer use in job queues; mixing json_decode() and unserialize() pipelines; round-tripping a value through another serializer before this one; refactors that changed where decoding happens so it now runs twice.

Related errors


AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21). Data as JSON: /api/errors/9a2f6790e04e2b81. Report an issue: GitHub.