getgrav/grav · error · RuntimeException

Flash has no directory

Error message

Flash has no directory

What it means

During FlexDirectoryForm initialization the form loads its FlexFormFlash (per-session upload/form state) and requires a directory from it. FlexFormFlash::init() restores the directory either from the stored flash JSON ('object.type' or 'directory.type' resolved through the Flex registry) or from config; if both fail, getDirectory() returns null and this RuntimeException is thrown. In practice the flash exists in the session but its flex context cannot be reconstructed.

Solutions

  1. Clear the stale flash: delete the form flash files (user/data/form-flash or via FormFlash::delete()) or log out/in to reset the session.
  2. Verify the flex type is still registered: $flex->getDirectory('type') must return a FlexDirectory in the new code.
  3. Pass 'directory' in the form/flash options when constructing the form so initialization does not depend on stored state.
  4. After renames, keep a back-compat alias for the old flex type or ask affected users to restart the form.

Example fix

// before
$form = FlexDirectoryForm::instance(['directory' => $directory, 'name' => 'config']);
$form->initialize(); // Flash has no directory (stale session flash)

// after
$flash = new FlexFormFlash($form->getFlash()->getUniqueId());
$flash->delete(); // discard stale flash, then re-init
$form = FlexDirectoryForm::instance(['directory' => $directory, 'name' => 'config']);
Defensive patterns

Strategy: validation

Validate before calling

// Ensure a clean flash before initializing a directory form
$flash = new \Grav\Framework\Flex\FlexFormFlash($uniqueId);
if ($flash->exists() && $flash->getDirectory() === null) {
    $flash->delete(); // stale/unresolvable flash: restart the form
}
$form = FlexDirectoryForm::instance(['directory' => $directory, 'name' => $name])->initialize();

Try / catch

try {
    $form->initialize();
} catch (\Grav\Framework\Flex\Exception\RuntimeException $e) {
    if (str_contains($e->getMessage(), 'Flash has no directory')) {
        $form->getFlash()->delete(); // clear state, re-init on next request
    }
}

Prevention

When it happens

Trigger: A flex type was renamed/removed between the request that created the flash and the request that renders the form (deploy while users had forms open); the flex directory is not registered in Grav's Flex object (missing blueprints/flex configuration); a stale session flash file created by another form id collision; session data persisted across a major Grav upgrade with an older flash schema.

Common situations: Deploying a plugin whose flex collection type changed name while admin users kept logged-in sessions; dev environment with long-lived sessions across code changes; flash files under user/data forming leftovers after uninstalling a flex plugin.

Related errors


AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17). Data as JSON: /api/errors/128589153a184faa. Report an issue: GitHub.

Appendix: source

Thrown at system/src/Grav/Framework/Flex/FlexDirectoryForm.php:128

     * @return $this
     */
    public function initialize()
    {
        $this->messages = [];
        $this->submitted = false;
        $this->data =  new Data($this->directory->loadDirectoryConfig($this->name), $this->getBlueprint());
        $this->files = [];
        $this->unsetFlash();

        /** @var FlexFormFlash $flash */
        $flash = $this->getFlash();
        if ($flash->exists()) {
            $data = $flash->getData();
            $includeOriginal = (bool)($this->getBlueprint()->form()['images']['original'] ?? null);

            $directory = $flash->getDirectory();
            if (null === $directory) {
                throw new RuntimeException('Flash has no directory');
            }
            $this->directory = $directory;
            $this->data = $data ? new Data($data, $this->getBlueprint()) : null;
            $this->files = $flash->getFilesByFields($includeOriginal);
        }

        return $this;
    }

    /**
     * @param string $uniqueId
     * @return void
     */
    public function setUniqueId(string $uniqueId): void
    {
        if ($uniqueId !== '') {
            $this->uniqueid = $uniqueId;
        }

View on GitHub (pinned to 6040efed04)