microsoft/qlib · warning · NotImplementedError
Render is not implemented in EnvWrapper.
Error message
Render is not implemented in EnvWrapper.
What it means
NotImplementedError from `EnvWrapper.render` (qlib/rl/utils/env_wrapper.py:250). The wrapper proxies reset/step to the underlying simulator plus interpreters, but rendering was never implemented, so any call — including generic RL tooling that renders by default — fails.
Source
Thrown at qlib/rl/utils/env_wrapper.py:250
self.status["reward_history"].append(rew)
if self.aux_info_collector is not None:
aux_info = self.aux_info_collector(sim_state)
else:
aux_info = {}
# Final logging stuff: RL-specific logs
if done:
self.logger.add_scalar("steps_per_episode", self.status["cur_step"])
self.logger.add_scalar("reward", rew)
self.logger.add_any("obs", obs, loglevel=LogLevel.DEBUG)
self.logger.add_any("policy_act", policy_action, loglevel=LogLevel.DEBUG)
info_dict = InfoDict(log=self.logger.logs(), aux_info=aux_info)
return obs, rew, done, info_dict
def render(self, mode: str = "human") -> None:
raise NotImplementedError("Render is not implemented in EnvWrapper.")
View on GitHub (pinned to 79633dd950)
Solutions
- Remove render calls; inspect simulator state and `logger` metrics (wrapper logs obs/reward per step) instead.
- Use the wrapper's `info_dict['log']` / LoggerWriter outputs to visualize training.
- If rendering is essential, subclass EnvWrapper and implement `render` from `self.simulator.get_state()` for your task.
Example fix
// before obs, rew, done, info = env.step(act) env.render() // NotImplementedError // after obs, rew, done, info = env.step(act) print(info["log"]) # use logged metrics instead of rendering
Defensive patterns
Strategy: type-guard
Validate before calling
def supports_render(env) -> bool:
return type(env).render is not object.__getattribute__(env, "render").__func__ # simplified
# simpler and sufficient:
def supports_render(env) -> bool:
import inspect
try:
return "Not implemented" not in inspect.getsource(type(env).render)
except (OSError, TypeError):
return True Type guard
from qlib.rl.utils.env_wrapper import EnvWrapper
def env_supports_render(env) -> bool:
return not isinstance(env, EnvWrapper) or type(env).render is not EnvWrapper.render Try / catch
try:
env.render(mode=mode)
except NotImplementedError:
log.debug("render unsupported; skipping visualization") Prevention
- Disable render in generic runners/watchers when using EnvWrapper.
- Visualize via the wrapper's logged metrics (info_dict['log']) instead.
- Subclass EnvWrapper and implement render from simulator state if you need visuals.
When it happens
Trigger: Calling `env.render()` or `env.render('human')` directly; using a tianshou/gym runner or experiment tracker with `render=True`; gym API conformance checks or wrappers that invoke render on reset/step.
Common situations: Reusing generic gym visualization utilities with qlib's wrapper; watch/monitor wrappers (RecordVideo etc.) applied around EnvWrapper; porting tutorial code from other gym environments that call render in the loop.
Related errors
- Implement reward calculation recipe in `reward()`.
- Seed iterator for training is not available.
- Seed iterator for validation is not available.
- Seed iterator for testing is not available.
- You can trying to get a state from a dead environment wrappe
AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15).
Data as JSON: /api/errors/ba5001abdd9ec153.
Report an issue: GitHub.