{"record":{"id":"59a8e25466b0ff3e","repo":"phalcon/cphalcon","slug":"the-request-method-is-not-allowed-for-the-matched","errorCode":null,"errorMessage":"The request method is not allowed for the matched route.","messagePattern":"The request method is not allowed for the matched route\\.","errorType":"exception","errorClass":"Phalcon\\ADR\\Exceptions\\MethodNotAllowed","httpStatus":405,"severity":"error","filePath":"phalcon/ADR/Router/Router.zep","lineNumber":164,"sourceCode":"        if this->actionDirectory === \"\" {\n            throw new ActionDirectoryNotSet();\n        }\n\n        let path   = request->getURI(true),\n            method = request->getMethod();\n\n        let located = this->locate(method, path);\n        if typeof located == \"array\" {\n            return new RouterMatch(\n                located[0],\n                located[1],\n                this->middlewareFor(located[0])\n            );\n        }\n\n        for other in this->verbs() {\n            if strcasecmp(other, method) !== 0 && typeof this->locate(other, path) == \"array\" {\n                throw new MethodNotAllowed();\n            }\n        }\n\n        return null;\n    }\n\n    public function methodFor(string className) -> string | null\n    {\n        var verb;\n\n        let verb = this->verbOf(className);\n\n        return null === verb ? null : strtoupper(verb);\n    }\n\n    public function pathFor(string className) -> string | null\n    {\n        var name, names, part, parts, path;","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/ADR/Router/Router.zep#L146-L182","documentation":"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.","triggerScenarios":"new QueryBuilderCursor(['limit' => 20, 'builder' => $builder]) with no 'cursorColumn' entry.","commonSituations":"Assuming the adapter defaults to the primary key 'id'; trimming config when migrating from the offset adapter; docs/examples that omit the key.","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()."],"exampleFix":"// before\n$paginator = new QueryBuilderCursor(\n    [\n        'limit'   => 20,\n        'builder' => $builder,\n    ]\n); // throws MissingRequiredParameter('cursorColumn')\n\n// after\n$builder->orderBy('id');\n$paginator = new QueryBuilderCursor(\n    [\n        'limit'        => 20,\n        'builder'      => $builder,\n        'cursorColumn' => 'id',\n    ]\n);","handlingStrategy":"validation","validationCode":"$config['cursorColumn'] ??= 'id'; // sensible default; the constructor has none\nif (!is_string($config['cursorColumn']) || $config['cursorColumn'] === '') {\n    throw new \\InvalidArgumentException('cursorColumn must be a non-empty string');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["paginator","cursor","config","validation"],"backgroundTag":"missing-required-parameter","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}