phalcon/cphalcon · error · Phalcon\Session\Adapter\Exceptions\AdapterRuntimeError

{last PHP error message}

Error message

{last PHP error message}

What it means

Stream::gc() globs '{savePath}/{prefix}*' to collect expired session files. glob() errors are suppressed (error_reporting(0) + error_clear_last), and when glob() still returns false the adapter throws AdapterRuntimeError carrying the last PHP error message (or 'Unexpected gc error' if none was recorded). The message is the raw PHP warning, e.g. an open_basedir restriction or permission denied on directory read.

Source

Thrown at phalcon/Session/Adapter/Stream.zep:140

     * @return false|int
     * @throws AdapterRuntimeError
     */
    public function gc(int max_lifetime) -> false | int
    {
        var file, glob, last, pattern, time;

        let pattern = this->path . this->prefix . "*",
            time    = time() - max_lifetime,
            glob    = this->getGlobFiles(pattern);

        if (false === glob) {
            let last = error_get_last();
            if (isset(last["message"])) {
                let last = last["message"];
            } else {
                let last = "Unexpected gc error";
            }
            throw new AdapterRuntimeError(last);
        }

        if (!empty(glob)) {
            for file in glob {
                if true === this->phpFileExists(file) &&
                   true === is_file(file)     &&
                   (filemtime(file) < time) {
                    this->phpUnlink(file);
                }
            }
        }

        return 1;
    }

    /**
    * Ignore the savePath and use local defined path
    */

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Read the exception message: it names the real PHP-level cause (open_basedir restriction, permission denied, No such file or directory)
  2. Recreate the directory and restore list+write permissions for the PHP user: mkdir -p and chmod/chown as for error 701
  3. Move savePath to a dedicated directory that tmp cleaners ignore, and register it in tmpfiles.d with an age rule matching session lifetime
  4. Add a health check that is_dir($savePath) && is_readable($savePath) && is_writable($savePath) before starting the session

Example fix

// before: gc explodes mid-request when the dir vanished
// after: self-heal before session start
$dir = '/var/lib/myapp/sessions';
if (!is_dir($dir)) { @mkdir($dir, 0770, true); }
$session->setAdapter(new Stream(['savePath' => $dir]));
Defensive patterns

Strategy: try-catch

Validate before calling

if (!is_dir($savePath) || !is_readable($savePath) || !is_writable($savePath)) {
    // recreate or alert before the session (and its gc) runs
    @mkdir($savePath, 0770, true);
}

Try / catch

try {
    $session->start();
} catch (\Phalcon\Session\Adapter\Exceptions\AdapterRuntimeError $e) {
    // $e->getMessage() is the raw glob() warning (open_basedir, permission denied, ...)
    $logger->error('Session gc failed: ' . $e->getMessage());
    // self-heal the directory and reject the request safely
    throw new ServiceUnavailableException('Session storage unavailable', 0, $e);
}

Prevention

When it happens

Trigger: Garbage collection runs on session_start() when session.gc_probability/session.gc_divisor hit, and the save directory has become unreadable since construction: deleted by a tmp cleaner while the worker still runs, permissions changed, open_basedir tightened, the path replaced by a file, or an unmounted network share.

Common situations: systemd-tmpfiles or docker tmp cleaners removing the session directory under long-lived workers; ops tightening open_basedir after the app bootstrapped; NFS/overlay filesystems returning glob errors; directories removed between deploys.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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