{"record":{"id":"e244432e9de0be11","repo":"phalcon/cphalcon","slug":"incompatible-acl-snapshot-version-version-exp","errorCode":null,"errorMessage":"Incompatible ACL snapshot version '{version}'; expected '{SNAPSHOT_VERSION}'","messagePattern":"Incompatible ACL snapshot version '(.+?)'; expected '(.+?)'","errorType":"exception","errorClass":"Phalcon\\Acl\\Exceptions\\InvalidSnapshot","httpStatus":null,"severity":"error","filePath":"phalcon/Acl/Adapter/Storage.zep","lineNumber":92,"sourceCode":"\n        let data = this->storage->get(this->key);\n\n        if typeof data === \"object\" {\n            let data = this->normalizeToArray(data);\n        }\n\n        if typeof data !== \"array\" {\n            return false;\n        }\n\n        if !isset data[\"version\"] {\n            return false;\n        }\n\n        let version = data[\"version\"];\n\n        if version != self::SNAPSHOT_VERSION {\n            throw new InvalidSnapshot(\n                \"Incompatible ACL snapshot version '\" . version .\n                \"'; expected '\" . self::SNAPSHOT_VERSION . \"'\"\n            );\n        }\n\n        if unlikely (\n            typeof data[\"access\"] !== \"array\" ||\n            typeof data[\"accessList\"] !== \"array\" ||\n            typeof data[\"components\"] !== \"array\" ||\n            typeof data[\"componentsNames\"] !== \"array\" ||\n            typeof data[\"roles\"] !== \"array\" ||\n            typeof data[\"roleInherits\"] !== \"array\"\n        ) {\n            throw new InvalidSnapshot(\"Malformed ACL snapshot structure\");\n        }\n\n        let rebuiltRoles = [];\n        for name, description in data[\"roles\"] {","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Acl/Adapter/Storage.zep#L74-L110","documentation":"QueueDestinationGuard::assertQueue() enforces a single rule shared by producers (send) and contexts (createConsumer): the destination must implement Phalcon\\Contracts\\Queue\\Queue. Any other DestinationInterface implementation — notably a Topic — triggers InvalidDestinationException, with the {action} slot in 'This transport can only {action} a Queue destination' telling you whether the send path or the consume path rejected it.","triggerScenarios":"$producer->send($context->createTopic('news'), $message) on a queue-only transport, or $context->createConsumer($topic) — the topic object passes the DestinationInterface type hint but fails the instanceof Queue check.","commonSituations":"Code written against queue-interop expecting topic support (RabbitMQ-style pub/sub) reused on a queue-only backend; variable destinations routed from config where 'topic' was selected; refactoring from an AMQP transport.","solutions":["Create the destination with createQueue('name') instead of createTopic('name') for this transport.","If you genuinely need publish/subscribe semantics, switch to a transport that implements topics.","Type-check the destination before calling send()/createConsumer() when destinations are dynamic."],"exampleFix":"// before\n$destination = $context->createTopic('orders');\n$producer->send($destination, $message); // InvalidDestinationException\n\n// after\n$destination = $context->createQueue('orders');\n$producer->send($destination, $message);","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isQueueDestination(\\Phalcon\\Contracts\\Queue\\Destination $destination): bool\n{\n    return $destination instanceof \\Phalcon\\Contracts\\Queue\\Queue;\n}\n\n// usage\nif (!isQueueDestination($destination)) {\n    throw new \\InvalidArgumentException(\n        'Queue-only transport: destination must be created with createQueue()'\n    );\n}\n$producer->send($destination, $message);","tryCatchPattern":"try {\n    $producer->send($destination, $message);\n} catch (\\Phalcon\\Queue\\Exceptions\\InvalidDestinationException $e) {\n    // message names the action: 'send to' or 'consume from'\n    // rebuild the destination with createQueue() and retry\n    $producer->send($context->createQueue($destination->getName()), $message);\n}","preventionTips":["For queue-only transports, always create destinations via createQueue().","Narrow destination variables to the Queue contract in your own signatures when targeting such transports."],"tags":["queue","destination","type-guard","pubsub"],"backgroundTag":"invalid-destination-type","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}