Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
Back to tool/Back to issues
#3440·hydra

hydra.mode discovery composes the config twice on every invocation

Author: omryCreated Sep 6, 2026Updated Sep 7, 2026

Description

Every Hydra app invocation composes its config twice.

_run_hydra needs to know the run mode before it can dispatch to run() or multirun(), so it calls Hydra.get_mode(), which composes a full config purely to read cfg.hydra.mode and then throws it away. The real composition then happens inside run() or multirun().

python
# hydra/_internal/utils.py
if args.run or args.multirun:
    run_mode = hydra.get_mode(config_name=config_name, overrides=overrides)
    _run_app(run=args.run, multirun=args.multirun, mode=run_mode, ...)
python
# hydra/_internal/hydra.py
def get_mode(self, config_name, overrides):
    try:
        cfg = self.compose_config(
            config_name=config_name,
            overrides=overrides,
            with_log_configuration=False,
            run_mode=RunMode.MULTIRUN,
            validate_sweep_overrides=False,
        )
        return cfg.hydra.mode
    except Exception:
        return None

Why it is written this way

This is not gratuitous. run_mode is an input to composition, so there is a genuine ordering problem: you cannot compose without a mode, and the mode may be declared inside the config, which you can only read by composing.

run_mode affects composition in two places:

  1. validate_sweep_overrides_legal: under RUN, x=1,2,3 is rejected as ambiguous; under MULTIRUN, sweeps over the hydra node are rejected.
  2. create_defaults_list(..., skip_missing=run_mode == RunMode.MULTIRUN). That flag decides whether a config group with a missing default is skipped or raises You must specify 'db', e.g, db=<OPTION>, so the composed defaults list itself differs by mode.

get_mode resolves this by composing in the permissive mode (MULTIRUN, hence skip_missing=True) with validation disabled, so the probe succeeds whichever mode turns out to be real.

Because the fallback is except Exception: return None, the cost is invisible: it affects latency, never correctness, and a failed probe silently defers to flag-based dispatch. It has been this way since #2085 (March 2022) and has never been reported.

Proposal

Require hydra.mode to come from the primary config or the command line, and read it without composing:

  • parse the overrides for a hydra.mode key, which needs no composition;
  • otherwise load only the primary config via ConfigRepository.load_config(config_name), which is one source lookup, one file read and one parse, with no defaults list traversal and therefore no dependence on the mode;
  • otherwise return None and let flag-based dispatch apply, exactly as today.

This removes the second composition rather than optimizing around it.

What this gives up

Worth deciding deliberately, since 2_multirun.md currently promises hydra.mode can be configured "in any supported way":

  1. hydra.mode set from a config group or a defaults list entry, for example an experiment config carrying hydra.mode: MULTIRUN, would stop working.
  2. hydra.mode as an interpolation referring to other config nodes would stop working, since nothing is composed. A literal or a self-contained resolver such as ${oc.env:...} is fine.

Neither path is exercised anywhere in this repo: no YAML here sets hydra.mode, and every test drives it through a command line override. The originating request, #394, only asked to default to multirun from Hydra's configuration, which the primary config satisfies.

Both losses are detectable, so this can fail loudly rather than silently.

Notes

  • The two compositions do not take identical input: _run_app appends hydra.mode=RUN or hydra.mode=MULTIRUN to the overrides before dispatching, so the second composition sees an override the probe never did.
  • The blanket except Exception should be narrowed as part of this. With a single file load the failure modes are small and enumerable.
  • Docs would need updating: website/docs/tutorials/basic/running_your_app/2_multirun.md.

Source: facebookresearch/hydra

View original on GitHubView discussion on GitHub