666ghj/MiroFish · error · RuntimeError
模拟停止未达到终态: {simulation_id}, status={state.runner_status}
Error message
模拟停止未达到终态: {simulation_id}, status={state.runner_status} What it means
Raised by stop_simulation when the run state's runner_status is neither FAILED nor STOPPED after the stop sequence finished — the stop did not converge to a terminal state. The message includes the simulation_id and the stuck status so you can tell whether it is stuck in STOPPING, PAUSED, etc.
Source
Thrown at backend/app/services/simulation_runner.py:1079
)
raise RuntimeError(state.error) from error
state.runner_status = RunnerStatus.STOPPED
state.twitter_running = False
state.reddit_running = False
state.completed_at = datetime.now().isoformat()
state.error = None
cls._save_run_state(state)
cls._sync_simulation_status(
simulation_id,
RunnerStatus.STOPPED,
)
cls._manual_stop_requests.discard(simulation_id)
state = cls.get_run_state(simulation_id) or state
if state.runner_status == RunnerStatus.FAILED:
raise RuntimeError(state.error or "模拟停止失败")
if state.runner_status != RunnerStatus.STOPPED:
raise RuntimeError(
f"模拟停止未达到终态: {simulation_id}, status={state.runner_status}"
)
logger.info(f"模拟已停止: {simulation_id}")
return state
@classmethod
def _read_actions_from_file(
cls,
file_path: str,
default_platform: Optional[str] = None,
platform_filter: Optional[str] = None,
agent_id: Optional[int] = None,
round_num: Optional[int] = None
) -> List[AgentAction]:
"""
从单个动作文件中读取动作
View on GitHub (pinned to b5b53acc57)
Solutions
- Read the status in the message: STOPPING usually means a finalizer is still running — poll get_run_state for a bounded period before concluding it is stuck.
- If genuinely stuck, inspect logs of the monitor/finalizer thread and the run-state file for the simulation, then force-cleanup: kill the process group and mark the state STOPPED via the recovery path.
- Report the stuck status value — it identifies which code path failed to reach a terminal state.
Example fix
// before
try:
SimulationRunner.stop_simulation(sim_id)
except RuntimeError as e:
raise // 模拟停止未达到终态 ... status=RunnerStatus.STOPPING
// after
try:
SimulationRunner.stop_simulation(sim_id)
except RuntimeError as e:
if "未达到终态" not in str(e):
raise
state = SimulationRunner.wait_terminal_state(sim_id, poll=5.0, max_wait=300)
if state.runner_status not in (RunnerStatus.STOPPED, RunnerStatus.FAILED):
SimulationRunner.force_cleanup(sim_id) # last resort Defensive patterns
Strategy: retry
Try / catch
try:
SimulationRunner.stop_simulation(sim_id)
except RuntimeError as e:
if "未达到终态" not in str(e):
raise
state = bounded_poll_terminal(sim_id, max_wait=300)
if state.runner_status not in (RunnerStatus.STOPPED, RunnerStatus.FAILED):
escalate_stuck_run(sim_id, state.runner_status) # force cleanup path Prevention
- Serialize stop requests per simulation (single owner for finalization).
- Poll for terminal state with a deadline instead of assuming immediate convergence.
- Alert on any run whose status stays non-terminal past the stop deadline.
When it happens
Trigger: A competing finalizer (monitor thread) transitioned the state back to a non-terminal value after the synchronous path set STOPPED; a bug in a status writer leaves runner_status as STOPPING/PAUSED; restart-recovery reconstructed a state that no path ever finalizes.
Common situations: Races between two stop requests or between stop and the monitor's finalization; partially updated run-state files after a crash; custom code that sets runner_status without completing the terminal transition.
Related errors
- 模拟未在运行: {simulation_id}, status={state.runner_status}
- 模拟已在运行或结束处理中: {simulation_id}
- 模拟不存在: {simulation_id}
- 模拟仍在停止中,图谱写入未在 {wait_timeout:.0f}s 内完成
- Zep图谱写入未完整完成: {error}
AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14).
Data as JSON: /api/errors/b30a34f8f369cafc.
Report an issue: GitHub.