{"record":{"id":"8e43982af507ea03","repo":"Unity-Technologies/ml-agents","slug":"continuous-nan-action-detected","errorCode":null,"errorMessage":"Continuous NaN action detected.","messagePattern":"Continuous NaN action detected\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"critical","filePath":"ml-agents/mlagents/trainers/policy/policy.py","lineNumber":126,"sourceCode":"    def remove_previous_action(self, agent_ids: List[GlobalAgentId]) -> None:\n        for agent_id in agent_ids:\n            if agent_id in self.previous_action_dict:\n                self.previous_action_dict.pop(agent_id)\n\n    def get_action(\n        self, decision_requests: DecisionSteps, worker_id: int = 0\n    ) -> ActionInfo:\n        raise NotImplementedError\n\n    @staticmethod\n    def check_nan_action(action: Optional[ActionTuple]) -> None:\n        # Fast NaN check on the action\n        # See https://stackoverflow.com/questions/6736590/fast-check-for-nan-in-numpy for background.\n        if action is not None:\n            d = np.sum(action.continuous)\n            has_nan = np.isnan(d)\n            if has_nan:\n                raise RuntimeError(\"Continuous NaN action detected.\")\n\n    @abstractmethod\n    def increment_step(self, n_steps):\n        pass\n\n    @abstractmethod\n    def get_current_step(self):\n        pass\n\n    @abstractmethod\n    def load_weights(self, values: List[np.ndarray]) -> None:\n        pass\n\n    @abstractmethod\n    def get_weights(self) -> List[np.ndarray]:\n        return []\n\n    @abstractmethod","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/Unity-Technologies/ml-agents/blob/3ecb446f75d1e7400eb404c562dc005d3164cffc/ml-agents/mlagents/trainers/policy/policy.py#L108-L144","documentation":"RuntimeError raised by Policy.check_nan_action when the continuous portion of an action contains NaN. It sums the continuous action array and checks with np.isnan — a fast NaN detection used after every inference to prevent NaN values from corrupting the training buffer and network weights. Called from get_action in the inference path.","triggerScenarios":"Any inference step where the policy's network outputs NaN in the continuous action head — usually caused by exploding/vanishing values, a learning rate that's too high, unnormalized observations (inf/NaN inputs), or a corrupted checkpoint loaded via --init-file.","commonSituations":"Training diverges mid-run after reward/observation magnitudes blow up; loading a partially-written or corrupt .pt checkpoint; environment sends NaN observations (sensor error) that propagate through the network.","solutions":["Inspect your observations for NaN/Inf before passing them to the policy (np.isnan(obs).any()); fix the environment or normalize observations.","Reduce the learning rate and/or gradient clipping in your trainer settings to stop divergence producing NaN weights.","If it appears at startup, re-export or retrain your .pt checkpoint — the loaded weights are likely corrupted.","Re-run training from an earlier checkpoint taken before NaNs appeared."],"exampleFix":"# before\naction = policy.get_action(decision_steps)  # crashes with NaN continuous actions\n# after\nobs = decision_steps.obs\nif any(np.isnan(o).any() for o in obs):\n    obs = [np.nan_to_num(o) for o in obs]\naction = policy.get_action(decision_steps)","handlingStrategy":"validation","validationCode":"import numpy as np\ndef observations_are_finite(decision_steps) -> bool:\n    return all(np.isfinite(o).all() for o in decision_steps.obs)","typeGuard":"def is_finite_action(action) -> bool:\n    import numpy as np\n    if action is None:\n        return True\n    return np.isfinite(np.sum(action.continuous))","tryCatchPattern":"try:\n    action_info = policy.get_action(decision_steps, worker_id)\nexcept RuntimeError as e:\n    if \"NaN\" in str(e):\n        logger.error(\"Policy produced NaN actions; restoring last good checkpoint\")\n        policy.load(last_good_checkpoint)","preventionTips":["Sanitize environment observations for NaN/Inf before inference","Use a lower learning rate and enable gradient clipping","Periodically snapshot checkpoints so you can roll back after divergence","Normalize observations (NetworkSettings.normalize) when input scales vary"],"tags":["ml-agents","nan","numerical-instability","training-divergence"],"backgroundTag":"nan-detected-in-action","analyzedSha":"3ecb446f75d1e7400eb404c562dc005d3164cffc","analyzedAt":"2026-09-02T16:33:12.832Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T21:17:11.164Z"}