microsoft/qlib · error · RuntimeError

You can trying to get a state from a dead environment wrappe

Error message

You can trying to get a state from a dead environment wrapper.

What it means

RuntimeError in `EnvWrapper.reset` (qlib/rl/utils/env_wrapper.py:154). The wrapper pulls the next initial state from `seed_iterator`; once the iterator is exhausted it is set to None, marking the wrapper dead (it should be recycled by the vector env). A reset on such a dead wrapper raises immediately instead of silently reusing stale state.

Source

Thrown at qlib/rl/utils/env_wrapper.py:154

        self.status: EnvWrapperStatus = cast(EnvWrapperStatus, None)

    @property
    def action_space(self) -> Space:
        return self.action_interpreter.action_space

    @property
    def observation_space(self) -> Space:
        return self.state_interpreter.observation_space

    def reset(self, **kwargs: Any) -> ObsType:
        """
        Try to get a state from state queue, and init the simulator with this state.
        If the queue is exhausted, generate an invalid (nan) observation.
        """

        try:
            if self.seed_iterator is None:
                raise RuntimeError("You can trying to get a state from a dead environment wrapper.")

            # TODO: simulator/observation might need seed to prefetch something
            # as only seed has the ability to do the work beforehands

            # NOTE: though logger is reset here, logs in this function won't work,
            # because we can't send them outside.
            # See https://github.com/thu-ml/tianshou/issues/605
            self.logger.reset()

            if self.seed_iterator is SEED_INTERATOR_MISSING:
                # no initial state
                initial_state = None
                self.simulator = cast(Callable[[], Simulator], self.simulator_fn)()
            else:
                initial_state = next(cast(Iterator[InitialStateType], self.seed_iterator))
                self.simulator = self.simulator_fn(initial_state)

            self.status = EnvWrapperStatus(

View on GitHub (pinned to 79633dd950)

Solutions

  1. Let the vector environment (e.g. qlib's BaseVectorEnv / tianshou runner) own wrapper recycling; never reset wrappers yourself after exhaustion.
  2. Ensure the seed iterator yields at least as many initial states as resets requested in the phase (train loop steps; FiniteVectorEnv sizes val/test to the iterator).
  3. In custom loops, track exhausted wrappers (reset returns a NaN observation when the iterator merely ends) and only treat the RuntimeError as a lifecycle bug to fix upstream.

Example fix

// before
for _ in range(n):
    obs = wrapper.reset()  # n > number of seeds -> dead wrapper
// after
while True:
    obs = wrapper.reset()
    if is_invalid(obs):  # queue exhausted: stop instead of resetting again
        break
Defensive patterns

Strategy: try-catch

Validate before calling

def safe_reset(wrapper):
    """Returns None when the wrapper is dead and should be recycled."""
    try:
        return wrapper.reset()
    except RuntimeError as e:
        if "dead environment wrapper" in str(e):
            return None
        raise

Type guard

def wrapper_is_alive(wrapper) -> bool:
    return wrapper.seed_iterator is not None

Try / catch

try:
    obs = wrapper.reset()
except RuntimeError as e:
    if "dead environment wrapper" in str(e):
        log.debug("wrapper exhausted; recycling")
    else:
        raise

Prevention

When it happens

Trigger: Calling `env_wrapper.reset()` after its seed iterator raised StopIteration (i.e., after the finite seed set was consumed); manually driving an EnvWrapper outside a proper vector-env lifecycle; holding references to wrappers that the vector env already retired.

Common situations: Custom training loops that manage envs themselves and lose track of which wrappers are exhausted; seed iterators yielding fewer states than the number of resets requested; async/stale references after a NestedExecutor restarts environments.

Related errors


AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15). Data as JSON: /api/errors/ccd3534c911057e8. Report an issue: GitHub.