getgrav/grav · error · RuntimeException

No backups defined...

Error message

No backups defined...

What it means

Backups::backup($id) loads the backup profile list from the configuration key backups.profiles (user/config/backups.yaml merged over system/config/backups.yaml) and indexes it by integer. If $id is not a key in that list — because the list is missing, null, or simply shorter than the id — it throws RuntimeException 'No backups defined...'. It is a configuration lookup failure, not a filesystem one.

Source

Thrown at system/src/Grav/Common/Backup/Backups.php:238

     */
    public static function backup($id = 0, ?callable $status = null, ?string $environment = null)
    {
        $grav = Grav::instance();

        // If environment is specified and different from current, reload config
        if ($environment && $environment !== $grav['config']->get('setup.environment')) {
            $grav->setup($environment);
            $grav['config']->reload();
        }

        $profiles = static::getBackupProfiles();
        /** @var UniformResourceLocator $locator */
        $locator = $grav['locator'];

        if (isset($profiles[$id])) {
            $backup = (object) $profiles[$id];
        } else {
            throw new RuntimeException('No backups defined...');
        }

        $name = $grav['inflector']->underscorize($backup->name);
        $date = date(static::BACKUP_DATE_FORMAT, time());
        $filename = trim((string) $name, '_') . '--' . $date . '.zip';
        $grav['backups']->setup();
        $destination = static::$backup_dir . DS . $filename;
        $max_execution_time = ini_set('max_execution_time', '600');
        $backup_root = $backup->root;

        if ($locator->isStream($backup_root)) {
            $backup_root = $locator->findResource($backup_root);
        } else {
            $backup_root = rtrim(GRAV_ROOT . $backup_root, DS) ?: DS;
        }

        if (!$backup_root || !file_exists($backup_root)) {
            throw new RuntimeException("Backup location: {$backup_root} does not exist...");

View on GitHub (pinned to 6040efed04)

Solutions

  1. Inspect Backups::getBackupProfiles() (i.e. config backups.profiles) and confirm the id you pass is a valid array key
  2. Restore or fix user/config/backups.yaml so profiles is a non-empty list with name/root/schedule fields
  3. Re-register scheduler jobs after changing profiles (the job list is rebuilt from the current config on each scheduler run)
  4. When calling backup($id, $status, $environment), verify the profile exists in that environment's config, not just the default one

Example fix

// before
Backups::backup($id); // throws when $id is stale

// after
$profiles = Backups::getBackupProfiles();
if (!is_array($profiles) || !isset($profiles[$id])) {
    throw new RuntimeException(sprintf('Backup profile %d not found in backups.profiles', $id));
}
Backups::backup($id);
Defensive patterns

Strategy: validation

Validate before calling

$profiles = Backups::getBackupProfiles();
if (!is_array($profiles) || !isset($profiles[$id])) {
    // log and bail out with a clear message instead of letting backup() throw
    return;
}

Try / catch

try {
    Backups::backup($id);
} catch (RuntimeException $e) {
    // covers 'No backups defined...', missing roots, and containment rejects
    $log->error('Backup failed: ' . $e->getMessage());
}

Prevention

When it happens

Trigger: Calling Backups::backup(2) when only two profiles exist (valid ids 0 and 1); running a scheduled job that was registered from an older profile list whose ids no longer exist (onSchedulerInitialized captures $id at schedule time); user/config/backups.yaml overriding profiles with an empty value; invoking the admin Backups tool task with a stale id after profiles were edited.

Common situations: Profiles were renamed/reordered so array keys shifted; backups.yaml was emptied or corrupted during a migration; a cron/scheduler job survived a config change that removed its profile; environment mismatch — backup() was called with an $environment whose config reload produced a different profile set.

Related errors


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