phalcon/cphalcon · warning · Phalcon\DataMapper\Pdo\Exception\OperationCancelled
Operation cancelled by a listener of '{eventName}'
Error message
Operation cancelled by a listener of '{eventName}' What it means
Before each major operation the connection fires a cancellable 'before' event (beforeQuery, beforeBeginTransaction, ...). If a listener stops the event and the manager returns false, fireBefore() throws OperationCancelled so the operation does not run. It is a control-flow exception: the database work was deliberately aborted, not failed.
Source
Thrown at phalcon/DataMapper/Pdo/Connection/AbstractConnection.zep:913
let this->profiler = profiler;
return this;
}
/**
* Fires a cancellable "before" event. A listener cancels by stopping the
* event and returning false; see Phalcon\DataMapper\Pdo\Events for the
* required idiom. The operation does not run when it is cancelled.
*
* @param string $eventName
* @param mixed|null $data
*
* @throws OperationCancelled
*/
protected function fireBefore(string eventName, var data = null) -> void
{
if this->fireManagerEvent(eventName, data, true) === false {
throw new OperationCancelled(eventName);
}
}
/**
* Bind a value using the proper PDO::PARAM_* type.
*
* @param \PDOStatement $statement
* @param mixed $name
* @param mixed $arguments
*/
protected function performBind(
<\PDOStatement> statement,
var name,
var arguments
) -> void {
var key, parameters, type;
let key = name;View on GitHub (pinned to b7419de9cd)
Solutions
- Fix the listener: return true (or nothing) when the operation should proceed; return false only to cancel deliberately
- Follow the exact listener idiom documented in Phalcon\DataMapper\Pdo\Events — stopping propagation alone is not what cancels, the false return is
- Catch OperationCancelled where aborted operations are expected (e.g., read-only mode) and handle it explicitly
- Do not blanket-catch generic Exception around queries — that would hide intentional cancellations and real PDO errors alike
Example fix
// before
$eventsManager->attach('beforeQuery', function ($event, $connection) {
return strpos($connection->getSqlStatement(), 'FORBIDDEN'); // bool -> cancels when false
});
// after
$eventsManager->attach('beforeQuery', function ($event, $connection) {
if (strpos($connection->getSqlStatement(), 'FORBIDDEN') !== false) {
$event->stop();
return false; // explicit, deliberate cancel
}
return true;
}); Defensive patterns
Strategy: try-catch
Try / catch
use Phalcon\DataMapper\Pdo\Exception\OperationCancelled;
try {
$connection->query($sql);
} catch (OperationCancelled $e) {
// a before-event listener deliberately vetoed the operation
$logger->warning('Query cancelled by listener: ' . $sql);
} Prevention
- Write before-event listeners to return true explicitly on the success path
- Only return false (with $event->stop()) when cancellation is the intended outcome
- Register a dedicated catch for OperationCancelled wherever policy listeners can veto operations
When it happens
Trigger: An EventsManager listener on beforeQuery/beforeBeginTransaction calls $event->stop() and returns false (query blacklist, read-only enforcement); a listener whose last expression is a falsy check result implicitly returned as false; listener code copied from Phalcon\Di-era samples with different return conventions.
Common situations: Read-only replica guards blocking writes; auditing listeners that veto forbidden statements; a debugging listener that unintentionally returns false and cancels every query.
Related errors
- Driver not supported [{driver}]
- Class '{className}' does not have a method '{name}'
- Cannot disconnect a Decorated connection instance
- Connection not found: {type}:{requested}
- Invalid bind parameter (1)
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/ca511be64b583a51.
Report an issue: GitHub.