{"record":{"id":"fa9bab311a94c9af","repo":"getgrav/grav","slug":"no-backups-defined","errorCode":null,"errorMessage":"No backups defined...","messagePattern":"No backups defined\\.\\.\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"system/src/Grav/Common/Backup/Backups.php","lineNumber":238,"sourceCode":"     */\n    public static function backup($id = 0, ?callable $status = null, ?string $environment = null)\n    {\n        $grav = Grav::instance();\n\n        // If environment is specified and different from current, reload config\n        if ($environment && $environment !== $grav['config']->get('setup.environment')) {\n            $grav->setup($environment);\n            $grav['config']->reload();\n        }\n\n        $profiles = static::getBackupProfiles();\n        /** @var UniformResourceLocator $locator */\n        $locator = $grav['locator'];\n\n        if (isset($profiles[$id])) {\n            $backup = (object) $profiles[$id];\n        } else {\n            throw new RuntimeException('No backups defined...');\n        }\n\n        $name = $grav['inflector']->underscorize($backup->name);\n        $date = date(static::BACKUP_DATE_FORMAT, time());\n        $filename = trim((string) $name, '_') . '--' . $date . '.zip';\n        $grav['backups']->setup();\n        $destination = static::$backup_dir . DS . $filename;\n        $max_execution_time = ini_set('max_execution_time', '600');\n        $backup_root = $backup->root;\n\n        if ($locator->isStream($backup_root)) {\n            $backup_root = $locator->findResource($backup_root);\n        } else {\n            $backup_root = rtrim(GRAV_ROOT . $backup_root, DS) ?: DS;\n        }\n\n        if (!$backup_root || !file_exists($backup_root)) {\n            throw new RuntimeException(\"Backup location: {$backup_root} does not exist...\");","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Common/Backup/Backups.php#L220-L256","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect Backups::getBackupProfiles() (i.e. config backups.profiles) and confirm the id you pass is a valid array key","Restore or fix user/config/backups.yaml so profiles is a non-empty list with name/root/schedule fields","Re-register scheduler jobs after changing profiles (the job list is rebuilt from the current config on each scheduler run)","When calling backup($id, $status, $environment), verify the profile exists in that environment's config, not just the default one"],"exampleFix":"// before\nBackups::backup($id); // throws when $id is stale\n\n// after\n$profiles = Backups::getBackupProfiles();\nif (!is_array($profiles) || !isset($profiles[$id])) {\n    throw new RuntimeException(sprintf('Backup profile %d not found in backups.profiles', $id));\n}\nBackups::backup($id);","handlingStrategy":"validation","validationCode":"$profiles = Backups::getBackupProfiles();\nif (!is_array($profiles) || !isset($profiles[$id])) {\n    // log and bail out with a clear message instead of letting backup() throw\n    return;\n}","typeGuard":null,"tryCatchPattern":"try {\n    Backups::backup($id);\n} catch (RuntimeException $e) {\n    // covers 'No backups defined...', missing roots, and containment rejects\n    $log->error('Backup failed: ' . $e->getMessage());\n}","preventionTips":["After editing backups.profiles, re-check scheduler registrations — jobs capture the profile id when built","Treat profile ids as unstable: key custom logic on profile name, not array index","When using the $environment argument, verify the profile exists under that environment's merged config"],"tags":["grav","backup","configuration","scheduler","runtimeexception"],"backgroundTag":"missing-config-value","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}