{"record":{"id":"75235ef1b7a6e0b6","repo":"phalcon/cphalcon","slug":"headers-have-already-been-sent-cannot-emit-the-re","errorCode":null,"errorMessage":"Headers have already been sent; cannot emit the response.","messagePattern":"Headers have already been sent; cannot emit the response\\.","errorType":"exception","errorClass":"Phalcon\\ADR\\Exceptions\\HeadersAlreadySent","httpStatus":null,"severity":"error","filePath":"phalcon/ADR/Emitter/SapiEmitter.zep","lineNumber":29,"sourceCode":" * @link    https://pmjones.io/adr/\n */\n\nnamespace Phalcon\\ADR\\Emitter;\n\nuse Phalcon\\ADR\\Exceptions\\HeadersAlreadySent;\nuse Phalcon\\Contracts\\ADR\\Emitter\\Emitter;\nuse Phalcon\\Http\\ResponseInterface;\n\n/**\n * Emits a response through the SAPI (headers + body via `Response::send()`).\n * Refuses to emit once headers have already been sent.\n */\nclass SapiEmitter implements Emitter\n{\n    public function emit(<ResponseInterface> response) -> void\n    {\n        if headers_sent() {\n            throw new HeadersAlreadySent();\n        }\n\n        response->send();\n    }\n}\n","sourceCodeStart":11,"sourceCodeEnd":35,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/ADR/Emitter/SapiEmitter.zep#L11-L35","documentation":"The cursor-based paginator Phalcon\\Paginator\\Adapter\\QueryBuilderCursor validates its constructor config and requires a 'limit' key (page size). If the config array has no 'limit' entry, MissingRequiredParameter('limit') is thrown immediately at construction time.","triggerScenarios":"new QueryBuilderCursor(['builder' => $builder, 'cursorColumn' => 'id']) — the 'limit' key is absent.","commonSituations":"Migrating config arrays from the offset-based QueryBuilder adapter and dropping a key; typos like 'Limit' or 'pageSize'; introducing the cursor adapter in a framework upgrade where the old config no longer matches.","solutions":["Add 'limit' => <int> to the constructor config array.","Check the other required keys in the same pass: 'builder' (a Phalcon\\Mvc\\Model\\Query\\Builder instance) and 'cursorColumn' (non-empty string) follow immediately after this check.","Build the config array from a single validated source so all required keys are present together."],"exampleFix":"// before\n$paginator = new QueryBuilderCursor(\n    [\n        'builder'      => $builder,\n        'cursorColumn' => 'id',\n    ]\n); // throws MissingRequiredParameter('limit')\n\n// after\n$paginator = new QueryBuilderCursor(\n    [\n        'limit'        => 20,\n        'builder'      => $builder,\n        'cursorColumn' => 'id',\n    ]\n);","handlingStrategy":"validation","validationCode":"$required = ['limit', 'builder', 'cursorColumn'];\nforeach ($required as $key) {\n    if (!array_key_exists($key, $config)) {\n        throw new \\InvalidArgumentException(\"QueryBuilderCursor config lacks '{$key}'\");\n    }\n}\n$paginator = new \\Phalcon\\Paginator\\Adapter\\QueryBuilderCursor($config);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Centralize paginator config building in one helper so required keys are never forgotten.","Write a construction smoke test for each adapter covering the exact config keys you use."],"tags":["paginator","cursor","config","validation"],"backgroundTag":"missing-required-parameter","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}