phalcon/cphalcon · error · Phalcon\ADR\Exceptions\HeadersAlreadySent

Headers have already been sent; cannot emit the response.

Error message

Headers have already been sent; cannot emit the response.

What it means

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.

Source

Thrown at phalcon/ADR/Emitter/SapiEmitter.zep:29

 * @link    https://pmjones.io/adr/
 */

namespace Phalcon\ADR\Emitter;

use Phalcon\ADR\Exceptions\HeadersAlreadySent;
use Phalcon\Contracts\ADR\Emitter\Emitter;
use Phalcon\Http\ResponseInterface;

/**
 * Emits a response through the SAPI (headers + body via `Response::send()`).
 * Refuses to emit once headers have already been sent.
 */
class SapiEmitter implements Emitter
{
    public function emit(<ResponseInterface> response) -> void
    {
        if headers_sent() {
            throw new HeadersAlreadySent();
        }

        response->send();
    }
}

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Add 'limit' => <int> to the constructor config array.
  2. 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.
  3. Build the config array from a single validated source so all required keys are present together.

Example fix

// before
$paginator = new QueryBuilderCursor(
    [
        'builder'      => $builder,
        'cursorColumn' => 'id',
    ]
); // throws MissingRequiredParameter('limit')

// after
$paginator = new QueryBuilderCursor(
    [
        'limit'        => 20,
        'builder'      => $builder,
        'cursorColumn' => 'id',
    ]
);
Defensive patterns

Strategy: validation

Validate before calling

$required = ['limit', 'builder', 'cursorColumn'];
foreach ($required as $key) {
    if (!array_key_exists($key, $config)) {
        throw new \InvalidArgumentException("QueryBuilderCursor config lacks '{$key}'");
    }
}
$paginator = new \Phalcon\Paginator\Adapter\QueryBuilderCursor($config);

Prevention

When it happens

Trigger: new QueryBuilderCursor(['builder' => $builder, 'cursorColumn' => 'id']) — the 'limit' key is absent.

Common situations: 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.

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


AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21). Data as JSON: /api/errors/75235ef1b7a6e0b6. Report an issue: GitHub.