{"record":{"id":"0ac6cbac2ce53235","repo":"FoundationAgents/MetaGPT","slug":"failed-to-step-minecraft-server","errorCode":null,"errorMessage":"Failed to step Minecraft server","messagePattern":"Failed to step Minecraft server","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"metagpt/environment/minecraft/minecraft_ext_env.py","lineNumber":174,"sourceCode":"        self.connected = True\n        # All the reset in step will be soft\n        self.reset_options[\"reset\"] = \"soft\"\n        self.pause()\n        return json.loads(returned_data)\n\n    @mark_as_writeable\n    def _step(self, code: str, programs: str = \"\") -> dict:\n        if not self.has_reset:\n            raise RuntimeError(\"Environment has not been reset yet\")\n        self.check_process()\n        self.unpause()\n        data = {\n            \"code\": code,\n            \"programs\": programs,\n        }\n        res = requests.post(f\"{self.server}/step\", json=data, timeout=self.request_timeout)\n        if res.status_code != 200:\n            raise RuntimeError(\"Failed to step Minecraft server\")\n        returned_data = res.json()\n        self.pause()\n        return json.loads(returned_data)\n\n    @mark_as_writeable\n    def pause(self) -> bool:\n        if self.mineflayer.is_running and not self.server_paused:\n            res = requests.post(f\"{self.server}/pause\")\n            if res.status_code == 200:\n                self.server_paused = True\n        return self.server_paused\n\n    @mark_as_writeable\n    def unpause(self) -> bool:\n        if self.mineflayer.is_running and self.server_paused:\n            res = requests.post(f\"{self.server}/pause\")\n            if res.status_code == 200:\n                self.server_paused = False","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/FoundationAgents/MetaGPT/blob/11cdf466d042aece04fc6cfd13b28e1a70341b1f/metagpt/environment/minecraft/minecraft_ext_env.py#L156-L192","documentation":"MinecraftExtEnv._step POSTs {code, programs} to the mineflayer bridge server's /step endpoint and raises RuntimeError('Failed to step Minecraft server') on any non-200 response. The wrapper unpauses the bot, sends the code, and pauses again; a failure means the Express bridge rejected or crashed executing the request rather than the game logic itself.","triggerScenarios":"await env.step(code) where the bridge returns 400/500: syntax errors in the injected JavaScript, bot not spawned (bridge started but never connected to Minecraft), server on a different port than mc_port, or the bridge process died and the connection is refused (requests raises before this check, but 5xx from a proxy lands here).","commonSituations":"Generated code strings that are not valid JavaScript; Minecraft server not running or bot disconnected mid-session; port mismatch between server config and the running bridge; bridge restarted externally while the env instance kept stale state.","solutions":["Check that the Minecraft server is up and the mineflayer bridge (index.js) is running on the expected port before stepping.","Validate/escape the code string — it is executed as JavaScript inside the bot; log it verbatim on failure to see what the bridge rejected.","Call await env.reset() to re-establish the bot connection if the bot dropped, then retry the step.","Look at the bridge process stdout/stderr — the HTTP response body usually carries the real exception but this wrapper discards it (res.text is not logged)."],"exampleFix":"# before\nobs = await env.step(\"bot.chatt('hi')\")  # typo -> bridge 500 -> RuntimeError\n\n# after\ncode = \"bot.chat('hi')\"\ntry:\n    obs = await env.step(code)\nexcept RuntimeError as e:\n    logger.error(\"step failed for code=%r\", code)\n    raise","handlingStrategy":"retry","validationCode":"def bridge_ready(server: str, timeout=2) -> bool:\n    import requests\n    try:\n        return requests.get(f\"{server}/\", timeout=timeout).status_code < 500\n    except requests.RequestException:\n        return False\n\nassert bridge_ready(env.server), f\"mineflayer bridge at {env.server} is not responding\"","typeGuard":null,"tryCatchPattern":"import asyncio\n\nasync def step_with_retry(env, code, attempts=3):\n    for i in range(attempts):\n        try:\n            return await env.step(code)\n        except RuntimeError as e:\n            if \"Failed to step\" not in str(e) or i == attempts - 1:\n                raise\n            logger.warning(\"step failed (attempt %d), re-resetting bot\", i + 1)\n            await env.reset()\n    raise RuntimeError(\"unreachable\")","preventionTips":["Health-check the bridge (GET on the Express server) before driving it.","Log the exact code string on every step failure — most failures are invalid JavaScript.","Re-reset the environment when the bot disconnects instead of retrying blind; transient 5xx from the bridge usually mean the bot is gone."],"tags":["python","minecraft","http","javascript-execution","environment"],"backgroundTag":null,"analyzedSha":"11cdf466d042aece04fc6cfd13b28e1a70341b1f","analyzedAt":"2026-08-14T23:20:02.994Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}