Unity-Technologies/ml-agents · error · KeyError
agent_id {agent_id} is not present in the TerminalSteps
Error message
agent_id {agent_id} is not present in the TerminalSteps What it means
TerminalSteps.__getitem__ raises KeyError when the requested agent_id is not among the agents that terminated this step. Like DecisionSteps, only ids present in the current terminal batch are valid keys in agent_id_to_index. The library raises this rather than returning a default so callers don't silently treat non-terminated agents as done.
Source
Thrown at ml-agents-envs/mlagents_envs/base_env.py:230
"""
if self._agent_id_to_index is None:
self._agent_id_to_index = {}
for a_idx, a_id in enumerate(self.agent_id):
self._agent_id_to_index[a_id] = a_idx
return self._agent_id_to_index
def __len__(self) -> int:
return len(self.agent_id)
def __getitem__(self, agent_id: AgentId) -> TerminalStep:
"""
returns the TerminalStep for a specific agent.
:param agent_id: The id of the agent
:returns: obs, reward, done, agent_id and optional action mask for a
specific agent
"""
if agent_id not in self.agent_id_to_index:
raise KeyError(f"agent_id {agent_id} is not present in the TerminalSteps")
agent_index = self._agent_id_to_index[agent_id] # type: ignore
agent_obs = []
for batched_obs in self.obs:
agent_obs.append(batched_obs[agent_index])
group_id = self.group_id[agent_index]
return TerminalStep(
obs=agent_obs,
reward=self.reward[agent_index],
interrupted=self.interrupted[agent_index],
agent_id=agent_id,
group_id=group_id,
group_reward=self.group_reward[agent_index],
)
def __iter__(self) -> Iterator[Any]:
yield from self.agent_id
@staticmethodView on GitHub (pinned to 3ecb446f75)
Solutions
- Guard with `if agent_id in terminal_steps:` before indexing.
- Only iterate terminal_steps.agent_id (the ids that actually finished) rather than all known ids.
- Treat absence from TerminalSteps as 'agent still active' and read its data from DecisionSteps.
Example fix
# before
obs, reward, done, id = terminal_steps[agent_id] # KeyError: agent still active
# after
if agent_id in terminal_steps:
obs, reward, done, id = terminal_steps[agent_id]
else:
active = decision_steps[agent_id] # still running Defensive patterns
Strategy: type-guard
Validate before calling
if agent_id not in terminal_steps.agent_id_to_index:
# agent did not terminate this step — still active Type guard
def is_terminal(ts, agent_id: int) -> bool:
return agent_id in ts.agent_id_to_index Try / catch
try:
result = terminal_steps[agent_id]
except KeyError:
result = None # not done yet Prevention
- Only read terminal data for ids in terminal_steps.agent_id
- Treat absence from TerminalSteps as active and use DecisionSteps
- Track episode state per agent id instead of unconditional indexing
When it happens
Trigger: Indexing terminal_steps[agent_id] where that agent did not end its episode on the current step — e.g. the agent is still active and appears in DecisionSteps instead.
Common situations: Unconditionally reading terminal_steps[agent_id] for every agent every step even though only a few terminate per step; assuming an agent finished when it merely produced a decision; ids that never existed (typo, stale id).
Related errors
- agent_id {agent_id} is not present in the DecisionSteps
- There was a problem reading a message in a SideChannel. Plea
- StatsSideChannel should never receive messages.
- The behavior {name} needs a continuous input of dimension {_
- The behavior {name} needs a discrete input of dimension {_ex
AI-assisted analysis of Unity-Technologies/ml-agents@3ecb446f75 (2026-09-02).
Data as JSON: /api/errors/3520e85a518e7a25.
Report an issue: GitHub.