Skip to content

Bug: get_factor_env() overwrites extra_volumes with empty dict, causing StopIteration in QTDockerEnv.prepare() #1428

Description

@newhwa

Description

Running rdagent fin_factor with Docker backend crashes immediately with StopIteration because get_factor_env() unconditionally overwrites the QlibDockerConf default extra_volumes with an empty dict.

Environment

  • rdagent version: 0.8.1.dev28
  • Python: 3.12
  • OS: Ubuntu 24.04 (WSL2)
  • Backend: Docker (MODEL_CoSTEER_env_type=docker)

Steps to Reproduce

  1. Install rdagent with default configuration
  2. Set MODEL_CoSTEER_env_type=docker in .env
  3. Ensure qlib data exists at ~/.qlib/qlib_data/cn_data
  4. Run:
    rdagent fin_factor --loop-n 3

Expected Behavior

QTDockerEnv should use its default extra_volumes from QlibDockerConf (mounting ~/.qlib/ to /root/.qlib/), and prepare() should succeed.

Actual Behavior

StopIteration

Full traceback:

rdagent/app/qlib_rd_loop/factor.py:54 in main
    factor_loop = FactorRDLoop(FACTOR_PROP_SETTING)
rdagent/components/workflow/rd_loop.py:34 in __init__
    scen: Scenario = import_class(PROP_SETTING.scen)()
rdagent/scenarios/qlib/experiment/factor_experiment.py:35 in __init__
    runtime_environment=self.get_runtime_environment(),
rdagent/scenarios/qlib/experiment/factor_experiment.py:102 in get_runtime_environment
    factor_env = get_factor_env()
rdagent/components/coder/factor_coder/config.py:53 in get_factor_env
    env.prepare()
rdagent/utils/env.py:1522 in prepare
    qlib_data_path = next(iter(self.conf.extra_volumes.keys()))

Root Cause

In rdagent/components/coder/factor_coder/config.py, get_factor_env():

def get_factor_env(
    conf_type: Optional[str] = None,
    extra_volumes: dict = {},   # default is empty dict
    ...
) -> Env:
    ...
    env = QTDockerEnv()  # QlibDockerConf sets extra_volumes = {"~/.qlib/": {"bind": "/root/.qlib/", "mode": "rw"}}
    env.conf.extra_volumes = extra_volumes.copy()  # BUG: unconditionally overwrites with {}
    ...
    env.prepare()  # next(iter(empty_dict.keys())) raises StopIteration

QTDockerEnv.__init__ uses QlibDockerConf() which correctly defines:

extra_volumes: dict = {
    str(Path("~/.qlib/").expanduser().resolve().absolute()): {
        "bind": "/root/.qlib/",
        "mode": "rw",
    }
}

But this default is immediately wiped out by get_factor_env().

Suggested Fix

Only override extra_volumes when the caller explicitly passes a non-empty value:

# Before (broken)
env.conf.extra_volumes = extra_volumes.copy()

# After (fixed)
if extra_volumes:
    env.conf.extra_volumes = extra_volumes.copy()

Alternatively, use None as the default sentinel (more idiomatic):

def get_factor_env(
    conf_type: Optional[str] = None,
    extra_volumes: Optional[dict] = None,
    ...
) -> Env:
    ...
    if extra_volumes is not None:
        env.conf.extra_volumes = extra_volumes.copy()

The same pattern likely exists in rdagent/components/coder/model_coder/config.pyget_model_env() may have the same bug.

Affected Files

  • rdagent/components/coder/factor_coder/config.py (line 51)
  • rdagent/components/coder/model_coder/config.py (likely same issue)
  • rdagent/utils/env.py (line 1522 — prepare() doesn't guard against empty extra_volumes)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions