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

  1. 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
  2. Restore the stock stream definitions: diff your streams.yaml against system/defaults and keep only additive, non-cyclic overrides
  3. Delete the compiled setup cache (cache/ directory) so init() starts from a clean slate
  4. 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

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


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