phalcon/cphalcon · error · Phalcon\ADR\Exceptions\MethodNotAllowed
The request method is not allowed for the matched route.
Error message
The request method is not allowed for the matched route.
What it means
QueryBuilderCursor requires an explicit 'cursorColumn' config key naming the column used for keyset pagination (the adapter appends 'WHERE [cursorColumn] > :cursor:'). Unlike older adapters there is no default here: if the key is missing or null, MissingRequiredParameter('cursorColumn') is thrown at construction.
Source
Thrown at phalcon/ADR/Router/Router.zep:164
if this->actionDirectory === "" {
throw new ActionDirectoryNotSet();
}
let path = request->getURI(true),
method = request->getMethod();
let located = this->locate(method, path);
if typeof located == "array" {
return new RouterMatch(
located[0],
located[1],
this->middlewareFor(located[0])
);
}
for other in this->verbs() {
if strcasecmp(other, method) !== 0 && typeof this->locate(other, path) == "array" {
throw new MethodNotAllowed();
}
}
return null;
}
public function methodFor(string className) -> string | null
{
var verb;
let verb = this->verbOf(className);
return null === verb ? null : strtoupper(verb);
}
public function pathFor(string className) -> string | null
{
var name, names, part, parts, path;View on GitHub (pinned to b7419de9cd)
Solutions
- Add 'cursorColumn' => 'id' (or your monotonic ordering column) to the config.
- Remember to also orderBy() the same column in the builder — keyset pagination only works on a column the query is sorted by.
- Pick a numeric column; non-numeric values are rejected later during paginate().
Example fix
// before
$paginator = new QueryBuilderCursor(
[
'limit' => 20,
'builder' => $builder,
]
); // throws MissingRequiredParameter('cursorColumn')
// after
$builder->orderBy('id');
$paginator = new QueryBuilderCursor(
[
'limit' => 20,
'builder' => $builder,
'cursorColumn' => 'id',
]
); Defensive patterns
Strategy: validation
Validate before calling
$config['cursorColumn'] ??= 'id'; // sensible default; the constructor has none
if (!is_string($config['cursorColumn']) || $config['cursorColumn'] === '') {
throw new \InvalidArgumentException('cursorColumn must be a non-empty string');
} Prevention
- Always set cursorColumn explicitly; do not assume a primary-key default.
- Keep cursorColumn in sync with the builder's orderBy() — keyset pagination requires sorted-on columns.
When it happens
Trigger: new QueryBuilderCursor(['limit' => 20, 'builder' => $builder]) with no 'cursorColumn' entry.
Common situations: Assuming the adapter defaults to the primary key 'id'; trimming config when migrating from the offset adapter; docs/examples that omit the key.
Understand the failure class
Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.
Related errors
- Headers have already been sent; cannot emit the response.
- No route matched the request.
- Invalid value for the accessList
- No action directory set; call setActionDirectory().
- Role '{roleName}' (to inherit) does not exist in the role li
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/59a8e25466b0ff3e.
Report an issue: GitHub.