# Buggy code
def launch(
    self, job_overrides: Sequence[Sequence[str]], initial_job_idx: int
) -> Sequence[JobReturn]:
    """
    :param job_overrides: a List of List<String>, where each inner list is the arguments for one job run.
    :param initial_job_idx: Initial job idx in batch.
    :return: an array of return values from run_job with indexes corresponding to the input list indexes.
    """
    setup_globals()
    assert self.config is not None
    assert self.config_loader is not None
    assert self.task_function is not None

    configure_log(self.config.hydra.hydra_logging, self.config.hydra.verbose)
    sweep_dir = Path(str(self.config.hydra.sweep.dir))
    sweep_dir.mkdir(parents=True, exist_ok=True)
    log.info(
        f"Example Launcher(foo={self.foo}, bar={self.bar}) is launching {len(job_overrides)} jobs locally"
    )
    log.info(f"Sweep output dir : {sweep_dir}")
    runs = []

    for idx, overrides in enumerate(job_overrides):
        idx = initial_job_idx + idx
        lst = " ".join(filter_overrides(overrides))
        log.info(f"\t#{idx} : {lst}")
        sweep_config = self.config_loader.load_sweep_config(
            self.config, list(overrides)
        )
        with open_dict(sweep_config):
            # This typically coming from the underlying scheduler (SLURM_JOB_ID for instance)
            # In that case, it will not be available here because we are still in the main process.
            # but instead should be populated remotely before calling the task_function.
            sweep_config.hydra.job.id = f"job_id_for_{idx}"
            sweep_config.hydra.job.num = idx
        HydraConfig.instance().set_config(sweep_config)

        # If your launcher is executing code in a different process, it is important to restore
        # the singleton state in the new process.
        # To do this, you will likely need to serialize the singleton state along with the other
        # parameters passed to the child process.

        # happening on this process (executing launcher)
        state = Singleton.get_state()

        # happening on the spawned process (executing task_function in run_job)
        Singleton.set_state(state)

        ret = run_job(
            config=sweep_config,
            task_function=self.task_function,
            job_dir_key="hydra.sweep.dir",
            job_subdir_key="hydra.sweep.subdir",
        )
        runs.append(ret)
        # reconfigure the logging subsystem for Hydra as the run_job call configured it for the Job.
        # This is needed for launchers that calls run_job in the same process and not spawn a new one.
        configure_log(self.config.hydra.hydra_logging, self.config.hydra.verbose)
    return runs


# Traceback (omegaconf.errors.ConfigKeyError)
Traceback (most recent call last):
File "/home/omry/dev/hydra/examples/configure_hydra/job_name/with_config_file_override.py", line 10, in experiment
print(HydraConfig.get().job_logging.handlers.file.filename)
omegaconf.errors.ConfigKeyError: str interpolation key 'hydra.job.name' not found
full_key: hydra.job_logging.handlers.file.filename
reference_type=Any
object_type=dict

# Fixed code
def launch(
    self, job_overrides: Sequence[Sequence[str]], initial_job_idx: int
) -> Sequence[JobReturn]:
    """
    :param job_overrides: a List of List<String>, where each inner list is the arguments for one job run.
    :param initial_job_idx: Initial job idx in batch.
    :return: an array of return values from run_job with indexes corresponding to the input list indexes.
    """
    setup_globals()
    assert self.config is not None
    assert self.config_loader is not None
    assert self.task_function is not None

    configure_log(self.config.hydra.hydra_logging, self.config.hydra.verbose)
    sweep_dir = Path(str(self.config.hydra.sweep.dir))
    sweep_dir.mkdir(parents=True, exist_ok=True)
    log.info(
        f"Example Launcher(foo={self.foo}, bar={self.bar}) is launching {len(job_overrides)} jobs locally"
    )
    log.info(f"Sweep output dir : {sweep_dir}")
    runs = []

    for idx, overrides in enumerate(job_overrides):
        idx = initial_job_idx + idx
        lst = " ".join(filter_overrides(overrides))
        log.info(f"\t#{idx} : {lst}")
        sweep_config = self.config_loader.load_sweep_config(
            self.config, list(overrides)
        )
        with open_dict(sweep_config):
            # This typically coming from the underlying scheduler (SLURM_JOB_ID for instance)
            # In that case, it will not be available here because we are still in the main process.
            # but instead should be populated remotely before calling the task_function.
            sweep_config.hydra.job.id = f"job_id_for_{idx}"
            sweep_config.hydra.job.num = idx

        # If your launcher is executing code in a different process, it is important to restore
        # the singleton state in the new process.
        # To do this, you will likely need to serialize the singleton state along with the other
        # parameters passed to the child process.

        # happening on this process (executing launcher)
        state = Singleton.get_state()

        # happening on the spawned process (executing task_function in run_job)
        Singleton.set_state(state)

        ret = run_job(
            config=sweep_config,
            task_function=self.task_function,
            job_dir_key="hydra.sweep.dir",
            job_subdir_key="hydra.sweep.subdir",
        )
        runs.append(ret)
        # reconfigure the logging subsystem for Hydra as the run_job call configured it for the Job.
        # This is needed for launchers that calls run_job in the same process and not spawn a new one.
        configure_log(self.config.hydra.hydra_logging, self.config.hydra.verbose)
    return runs