phalcon/cphalcon · error · Phalcon\Session\Exceptions\SessionAlreadyStarted

The session has already been started. To change the id, use…

Error message

The session has already been started. To change the id, use regenerateId()

What it means

Manager::setId() assigns a new session id before the session starts; once a session is active (Manager::exists() true, session_status active) the id is already in use, so Phalcon throws SessionAlreadyStarted and points you to regenerateId().

Solutions

  1. Call setId() before start(), immediately after creating the Manager and setting the adapter
  2. To rotate the id of a live session (session fixation defense) use $session->regenerateId(true)
  3. Disable session.auto_start so the Manager owns session startup
  4. Guard the call: if (!$session->exists()) { $session->setId($id); }

Example fix

// before
$session->start();
$session->setId($newId); // SessionAlreadyStarted

// after
if (!$session->exists()) {
    $session->setId($newId);
}
$session->start();
// rotating an already-active session id:
$session->regenerateId(true);
Defensive patterns

Strategy: validation

Validate before calling

if (!$session->exists()) {
    $session->setId($newId);
}
// rotating an active session:
if ($session->exists()) {
    $session->regenerateId(true);
}

Prevention

When it happens

Trigger: Calling $session->setId($id) after $session->start(); PHP auto-starting sessions via session.auto_start=1 so any later setId throws; middleware that pins a custom id running after the session middleware already started the session.

Common situations: Enabling session.auto_start in php.ini or the FPM pool; porting plain-PHP code that called session_id() after session_start(); two components (auth listener and bootstrap) both configuring the session, one too late.

Related errors


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

Appendix: source

Thrown at phalcon/Session/Manager.zep:275

     */
    public function setAdapter(<SessionHandlerInterface> adapter) -> <ManagerInterface>
    {
        let this->adapter = adapter;

        return this;
    }

    /**
     * Set session Id
     *
     * @return ManagerInterface
     * @throws InvalidSessionId
     * @throws SessionAlreadyStarted
     */
    public function setId(string sessionId) -> <ManagerInterface>
    {
        if unlikely (true === this->exists()) {
            throw new SessionAlreadyStarted();
        }

        if unlikely !preg_match("/^[a-zA-Z0-9,-]+$/D", sessionId) {
            throw new InvalidSessionId();
        }

        session_id(sessionId);

        return this;
    }

    /**
     * Set the session name. Throw exception if the session has started
     * and do not allow poop names
     *
     * @param string $name
     *
     * @return ManagerInterface

View on GitHub (pinned to b7419de9cd)