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
- Install rdagent with default configuration
- Set
MODEL_CoSTEER_env_type=docker in .env
- Ensure qlib data exists at
~/.qlib/qlib_data/cn_data
- 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
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.py — get_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)
Description
Running
rdagent fin_factorwith Docker backend crashes immediately withStopIterationbecauseget_factor_env()unconditionally overwrites theQlibDockerConfdefaultextra_volumeswith an empty dict.Environment
MODEL_CoSTEER_env_type=docker)Steps to Reproduce
MODEL_CoSTEER_env_type=dockerin.env~/.qlib/qlib_data/cn_dataExpected Behavior
QTDockerEnvshould use its defaultextra_volumesfromQlibDockerConf(mounting~/.qlib/to/root/.qlib/), andprepare()should succeed.Actual Behavior
Full traceback:
Root Cause
In
rdagent/components/coder/factor_coder/config.py,get_factor_env():QTDockerEnv.__init__usesQlibDockerConf()which correctly defines:But this default is immediately wiped out by
get_factor_env().Suggested Fix
Only override
extra_volumeswhen the caller explicitly passes a non-empty value:Alternatively, use
Noneas the default sentinel (more idiomatic):The same pattern likely exists in
rdagent/components/coder/model_coder/config.py—get_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 emptyextra_volumes)