getgrav/grav · critical · RuntimeException
Setup: Configuration reload loop detected!
Error message
Setup: Configuration reload loop detected!
What it means
During Setup::init(), Grav repeatedly re-initializes the resource locator and re-scans config://streams.yaml, expecting the discovered file list to stabilize (the loop breaks when two consecutive lookups return the same $files). A $guard counter of 5 iterations prevents infinite recursion: if the streams.yaml lookup keeps yielding a different result every time — typically because stream definitions keep changing how config:// itself resolves — the guard runs out and RuntimeException 'Setup: Configuration reload loop detected!' is thrown. It indicates a cyclic or self-referential stream configuration.
Source
Thrown at system/src/Grav/Common/Config/Setup.php:325
$this->initializeLocator($locator);
$files = $locator->findResources('config://streams.yaml');
if ($check === $files) {
break;
}
// Update streams.
foreach (array_reverse($files) as $path) {
$file = CompiledYamlFile::instance($path);
$content = (array)$file->content();
if (!empty($content['schemes'])) {
$this->items['streams']['schemes'] = $content['schemes'] + $this->items['streams']['schemes'];
}
}
} while (--$guard);
if (!$guard) {
throw new RuntimeException('Setup: Configuration reload loop detected!');
}
// Make sure we have valid setup.
$this->check($locator);
return $this;
}
/**
* Initialize resource locator by using the configuration.
*
* @param UniformResourceLocator $locator
* @return void
* @throws BadMethodCallException
*/
public function initializeLocator(UniformResourceLocator $locator)
{
$locator->reset();View on GitHub (pinned to 6040efed04)
Solutions
- Inspect every streams.yaml that participates in the config stream (user/config/streams.yaml, user/env/*/config/streams.yaml, plugin-supplied ones) and remove any scheme redefinition that references config:// or chains back into it
- Restore the stock stream definitions: diff your streams.yaml against system/defaults and keep only additive, non-cyclic overrides
- Delete the compiled setup cache (cache/ directory) so init() starts from a clean slate
- Disable recently added plugins one by one to find which one introduces the cyclic stream definition
Example fix
# user/config/streams.yaml — before (cyclic: redefines config:// pulling in another streams.yaml)
streams:
schemes:
config:
type: ReadOnlyStream
prefixes:
'': ['environment://config', 'user://config', 'system://config', 'user://extra-config']
# after — drop the override entirely; the built-in defaults are already correct
# (delete the file, or keep only non-config scheme overrides) Defensive patterns
Strategy: try-catch
Try / catch
try {
$setup->init();
} catch (RuntimeException $e) {
if (str_contains($e->getMessage(), 'reload loop')) {
// cyclic streams.yaml — fail fast with an ops alert instead of a white page
http_response_code(503);
error_log('Grav setup loop: check config://streams.yaml for cyclic scheme overrides');
}
throw $e;
} Prevention
- Never redefine the config scheme inside streams.yaml in a way that adds new directories containing further streams.yaml files
- Review plugin-supplied streams.yaml files before enabling new plugins in multi-environment setups
- Clear cache/ after any stream-configuration change so init() rebuilds deterministically
When it happens
Trigger: A user/config/streams.yaml (or one discovered via the config stream) that redefines the config scheme so each pass resolves config://streams.yaml to a different file set (e.g. chaining config:// to another directory that contains its own streams.yaml which redefines config again); environments or plugins layering contradictory stream prefixes; a stream path that only exists after another stream is initialized, so the list keeps growing.
Common situations: Hand-edited streams.yaml with self-referential config scheme overrides; a plugin or skeleton shipping a streams.yaml that conflicts with the site's; multi-environment setups (user/env/<host>/config/streams.yaml) creating alternating resolution orders; corrupted cache://compiled setup state left from an interrupted run.
Related errors
- Configuration is missing streams.schemes!
- Configuration is missing keys %s from streams.schemes!
- No backups defined...
- Backup location: {$backup_root} does not exist...
- Cache folder not defined.
AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17).
Data as JSON: /api/errors/4936decc63fff45d.
Report an issue: GitHub.