phpmyadmin/phpmyadmin · error · RuntimeException

Session not found.

Error message

Session not found.

What it means

FlashMessenger stores its messages in the PHP superglobal $_SESSION. initSessionStorage() bails out early if a storage reference already exists, and throws RuntimeException('Session not found.') when $_SESSION is not set — meaning session_start() was never called or the session was closed. This guards against silently losing flash messages.

Solutions

  1. Call session_start() before any FlashMessenger usage (ideally early in the bootstrap).
  2. Ensure no code calls session_write_close()/session_abort() before flash messages are read or written; move those calls after message handling.
  3. Enable session.use_strict_mode-compatible startup or set session.auto_start only if appropriate; otherwise explicitly start the session in tests/CLI before touching FlashMessenger.
  4. Check that the session save handler works and that $_SESSION is actually populated (var_dump(isset($_SESSION))).

Example fix

// before
$messenger = new FlashMessenger();
$messenger->addMessage('Saved'); // RuntimeException: Session not found.

// after
if (session_status() !== PHP_SESSION_ACTIVE) {
    session_start();
}
$messenger = new FlashMessenger();
$messenger->addMessage('Saved');
Defensive patterns

Strategy: validation

Validate before calling

if (session_status() !== PHP_SESSION_ACTIVE) {
    session_start(); // must run before any FlashMessenger usage
}
if (!isset($_SESSION)) {
    throw new RuntimeException('Session unavailable; cannot use flash messages.');
}

Type guard

function sessionIsActive(): bool
{
    return session_status() === PHP_SESSION_ACTIVE && isset($_SESSION);
}

Try / catch

try {
    $messenger->addMessage('Saved');
} catch (RuntimeException $e) {
    if (str_contains($e->getMessage(), 'Session not found')) {
        session_start();
        $messenger->addMessage('Saved'); // retry once after starting the session
    } else {
        throw $e;
    }
}

Prevention

When it happens

Trigger: Calling addMessage, getMessages, or getCurrentMessages (or any code that does) before session_start() has run, after session_write_close()/session_abort(), or in a CLI/test context where no session was started.

Common situations: Session autostart disabled (session.auto_start=0) and no session_start() in bootstrap; flash message used after the response is sent and the session closed; long-running scripts that closed the session to unlock it; unit tests invoking FlashMessenger without a session fixture.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of phpmyadmin/phpmyadmin@70d713dc39 (2026-09-13). Data as JSON: /api/errors/b5142faf2d9c71a3. Report an issue: GitHub.

Appendix: source

Thrown at src/FlashMessenger.php:31

final class FlashMessenger
{
    private const STORAGE_KEY = 'FlashMessenger';

    /** @var mixed[] */
    private array|null $storage = null;

    /** @psalm-var FlashMessageList */
    private array $previousMessages = [];

    /** @psalm-assert !null $this->storage */
    private function initSessionStorage(): void
    {
        if ($this->storage !== null) {
            return;
        }

        if (! isset($_SESSION)) {
            throw new RuntimeException(__('Session not found.'));
        }

        $this->storage = &$_SESSION;

        if (isset($this->storage[self::STORAGE_KEY])) {
            $this->previousMessages = $this->storage[self::STORAGE_KEY];
        }

        $this->storage[self::STORAGE_KEY] = [];
    }

    public function addMessage(string $context, string $message, string $statement = ''): void
    {
        $this->initSessionStorage();

        $this->storage[self::STORAGE_KEY][] = ['context' => $context, 'message' => $message, 'statement' => $statement];
    }

View on GitHub (pinned to 70d713dc39)