{"record":{"id":"ce9473f507eb8660","repo":"Unity-Technologies/ml-agents","slug":"observation-at-index-obs-index-for-agent-with-id","errorCode":null,"errorMessage":"Observation at index={obs_index} for agent with id={agent_info.id} didn't match the ObservationSpec. Expected shape {expected_obs_shape} but got {agent_obs_shape}.","messagePattern":"Observation at index=(.+?) for agent with id=(.+?) didn't match the ObservationSpec\\. Expected shape (.+?) but got (.+?)\\.","errorType":"exception","errorClass":"UnityObservationException","httpStatus":null,"severity":"error","filePath":"ml-agents-envs/mlagents_envs/rpc_utils.py","lineNumber":208,"sourceCode":"        if actual_channels > expected_channels:\n            img = img[0:expected_channels, ...]\n    return img\n\n\ndef _check_observations_match_spec(\n    obs_index: int,\n    observation_spec: ObservationSpec,\n    agent_info_list: Collection[AgentInfoProto],\n) -> None:\n    \"\"\"\n    Check that all the observations match the expected size.\n    This gives a nicer error than a cryptic numpy error later.\n    \"\"\"\n    expected_obs_shape = tuple(observation_spec.shape)\n    for agent_info in agent_info_list:\n        agent_obs_shape = tuple(agent_info.observations[obs_index].shape)\n        if expected_obs_shape != agent_obs_shape:\n            raise UnityObservationException(\n                f\"Observation at index={obs_index} for agent with \"\n                f\"id={agent_info.id} didn't match the ObservationSpec. \"\n                f\"Expected shape {expected_obs_shape} but got {agent_obs_shape}.\"\n            )\n\n\n@timed\ndef _observation_to_np_array(\n    obs: ObservationProto, expected_shape: Optional[Iterable[int]] = None\n) -> np.ndarray:\n    \"\"\"\n    Converts observation proto into numpy array of the appropriate size.\n    :param obs: observation proto to be converted\n    :param expected_shape: optional shape information, used for sanity checks.\n    :return: processed numpy array of observation from environment\n    \"\"\"\n    if expected_shape is not None:\n        if list(obs.shape) != list(expected_shape):","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/Unity-Technologies/ml-agents/blob/3ecb446f75d1e7400eb404c562dc005d3164cffc/ml-agents-envs/mlagents_envs/rpc_utils.py#L190-L226","documentation":"UnityObservationException raised by _check_observations_match_spec when an agent's observation vector's shape doesn't match the ObservationSpec declared by the Behavior for that observation index. This preempts a confusing downstream numpy error by validating shapes eagerly.","triggerScenarios":"steps_from_proto processing agent steps where agent_info.observations[i].shape != observation_spec[i].shape for a given behavior — Unity sent data inconsistent with the spec it advertised at init.","commonSituations":"Changing the number of cameras/sensors or resolutions in Unity mid-run while reusing an old Python-side BehaviorSpec; stale environment instance after recompiling the Unity project; version mismatch corrupting the spec/data relationship.","solutions":["Restart the UnityEnvironment so the BehaviorSpec is re-fetched from the freshly-launched environment.","Ensure agents in the scene all use the same camera resolution/stacking and sensor configuration as at initialization.","Match com.unity.ml-agents and mlagents-envs versions; rebuild the executable after scene changes.","Call env.reset() after modifying behavior parameters in the Unity editor before stepping."],"exampleFix":"// before\nenv = UnityEnvironment(...)  # spec fetched\n# Unity scene edited: camera height changed 84 -> 96\nenv.step()  # shape mismatch\n// after\nenv.close()\nenv = UnityEnvironment(...)  # fresh spec matches observations","handlingStrategy":"try-catch","validationCode":"def specs_look_fresh(env, behavior):\n    spec = env.behavior_specs[behavior]\n    return spec.observation_specs is not None  # spec exists; refresh env if scene changed","typeGuard":null,"tryCatchPattern":"from mlagents_envs.exception import UnityObservationException\n\ntry:\n    env.step()\nexcept UnityObservationException as e:\n    if \"didn't match the ObservationSpec\" in str(e):\n        env.close()\n        env = UnityEnvironment(file_name=env_path)\n        env.reset()","preventionTips":["Never edit Unity scene/agent sensor configs while a Python session holds the env; relaunch instead.","Ensure all agents sharing a behavior name have identical observation setups.","Call env.reset() after editor-side changes.","Pin package versions across Unity and Python."],"tags":["python","unity-ml-agents","observation","shape-mismatch"],"backgroundTag":"observation-shape-mismatch","analyzedSha":"3ecb446f75d1e7400eb404c562dc005d3164cffc","analyzedAt":"2026-09-02T16:33:12.832Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T21:17:11.164Z"}