phalcon/cphalcon · error · Phalcon\Acl\Exceptions\InvalidSnapshot
Incompatible ACL snapshot version '{version}'; expected '{SN
Error message
Incompatible ACL snapshot version '{version}'; expected '{SNAPSHOT_VERSION}' What it means
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.
Source
Thrown at phalcon/Acl/Adapter/Storage.zep:92
let data = this->storage->get(this->key);
if typeof data === "object" {
let data = this->normalizeToArray(data);
}
if typeof data !== "array" {
return false;
}
if !isset data["version"] {
return false;
}
let version = data["version"];
if version != self::SNAPSHOT_VERSION {
throw new InvalidSnapshot(
"Incompatible ACL snapshot version '" . version .
"'; expected '" . self::SNAPSHOT_VERSION . "'"
);
}
if unlikely (
typeof data["access"] !== "array" ||
typeof data["accessList"] !== "array" ||
typeof data["components"] !== "array" ||
typeof data["componentsNames"] !== "array" ||
typeof data["roles"] !== "array" ||
typeof data["roleInherits"] !== "array"
) {
throw new InvalidSnapshot("Malformed ACL snapshot structure");
}
let rebuiltRoles = [];
for name, description in data["roles"] {View on GitHub (pinned to b7419de9cd)
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.
Example fix
// before
$destination = $context->createTopic('orders');
$producer->send($destination, $message); // InvalidDestinationException
// after
$destination = $context->createQueue('orders');
$producer->send($destination, $message); Defensive patterns
Strategy: type-guard
Type guard
function isQueueDestination(\Phalcon\Contracts\Queue\Destination $destination): bool
{
return $destination instanceof \Phalcon\Contracts\Queue\Queue;
}
// usage
if (!isQueueDestination($destination)) {
throw new \InvalidArgumentException(
'Queue-only transport: destination must be created with createQueue()'
);
}
$producer->send($destination, $message); Try / catch
try {
$producer->send($destination, $message);
} catch (\Phalcon\Queue\Exceptions\InvalidDestinationException $e) {
// message names the action: 'send to' or 'consume from'
// rebuild the destination with createQueue() and retry
$producer->send($context->createQueue($destination->getName()), $message);
} Prevention
- For queue-only transports, always create destinations via createQueue().
- Narrow destination variables to the Queue contract in your own signatures when targeting such transports.
When it happens
Trigger: $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.
Common situations: 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.
Related errors
- Role '{roleName}' (to inherit) produces an infinite loop
- Role must be either a string or implement RoleInterface
- Access '{accessName}' does not exist in component '{componen
- Access '{access}' does not exist in component '{componentNam
- {elementName} '{element}' does not exist in the {suffix}
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/e244432e9de0be11.
Report an issue: GitHub.