{"record":{"id":"53c721b45f4cb5c8","repo":"666ghj/MiroFish","slug":"prepare","errorCode":null,"errorMessage":"模拟配置不存在，请先调用 /prepare 接口","messagePattern":"模拟配置不存在，请先调用 /prepare 接口","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/app/services/simulation_runner.py","lineNumber":397,"sourceCode":"        \"\"\"\n        启动模拟\n        \n        Args:\n            simulation_id: 模拟ID\n            platform: 运行平台 (twitter/reddit/parallel)\n            max_rounds: 最大模拟轮数（可选，用于截断过长的模拟）\n            enable_graph_memory_update: 是否将Agent活动动态更新到Zep图谱\n            graph_id: Zep图谱ID（启用图谱更新时必需）\n            \n        Returns:\n            SimulationRunState\n        \"\"\"\n        # 加载模拟配置\n        sim_dir = os.path.join(cls.RUN_STATE_DIR, simulation_id)\n        config_path = os.path.join(sim_dir, \"simulation_config.json\")\n        \n        if not os.path.exists(config_path):\n            raise ValueError(f\"模拟配置不存在，请先调用 /prepare 接口\")\n        \n        with open(config_path, 'r', encoding='utf-8') as f:\n            config = json.load(f)\n        \n        # 初始化运行状态\n        time_config = config.get(\"time_config\", {})\n        total_hours = time_config.get(\"total_simulation_hours\", 72)\n        minutes_per_round = time_config.get(\"minutes_per_round\", 30)\n        total_rounds = int(total_hours * 60 / minutes_per_round)\n        \n        # 如果指定了最大轮数，则截断\n        if max_rounds is not None and max_rounds > 0:\n            original_rounds = total_rounds\n            total_rounds = min(total_rounds, max_rounds)\n            if total_rounds < original_rounds:\n                logger.info(f\"轮数已截断: {original_rounds} -> {total_rounds} (max_rounds={max_rounds})\")\n        \n        state = SimulationRunState(","sourceCodeStart":379,"sourceCodeEnd":415,"githubUrl":"https://github.com/666ghj/MiroFish/blob/b5b53acc57189a4a42e44a23e149dc655c98fe82/backend/app/services/simulation_runner.py#L379-L415","documentation":"Raised in SimulationRunner (class method starting a run): it looks for simulation_config.json under the run-state directory for the simulation id, and if the file is absent raises ValueError telling the user to call /prepare first. The run stage depends on artifacts (config JSON, profiles) produced by the earlier prepare stage; running without them is a workflow-order violation.","triggerScenarios":"Calling start/run on a simulation whose prepare never completed or failed (e.g. failed at error 33); prepare wrote config to a different directory than RUN_STATE_DIR/simulation_id; state directory reset between prepare and run; wrong simulation_id.","commonSituations":"Frontend lets the user press 'run' before prepare finishes; prepare failed silently and the user retried the wrong stage; container/volume mismatch losing prepared artifacts; concurrent env reset.","solutions":["Call the /prepare endpoint for this simulation and wait for success before starting the run.","If prepare failed, read its error (state.error) and fix the underlying cause first (often errors 32/33/30).","Verify simulation_config.json exists under the runner's RUN_STATE_DIR/<simulation_id>/; if the directory moved, align prepare and runner paths.","In the UI, disable the run action until prepare reports success."],"exampleFix":"# before\nrunner.start_simulation(sim_id, ...)  # ValueError: 模拟配置不存在\n# after\nconfig_path = os.path.join(SimulationRunner.RUN_STATE_DIR, sim_id, 'simulation_config.json')\nif not os.path.exists(config_path):\n    manager.prepare_simulation(sim_id, ...)  # produce config first\nrunner.start_simulation(sim_id, ...)","handlingStrategy":"validation","validationCode":"config_path = os.path.join(SimulationRunner.RUN_STATE_DIR, simulation_id, 'simulation_config.json')\nif not os.path.exists(config_path):\n    raise HTTPException(409, 'prepare must complete before starting the run')","typeGuard":null,"tryCatchPattern":"try:\n    SimulationRunner.start_simulation(sim_id, ...)\nexcept ValueError as e:\n    if '请先调用 /prepare' in str(e):\n        raise HTTPException(409, str(e)) from e\n    raise","preventionTips":["Enforce the prepare->run workflow in the UI (disable run until prepare succeeds).","Check prepare's persisted status/error before allowing start.","Keep prepare artifacts and run state on the same persistent volume."],"tags":["simulation","workflow-order","config","not-found"],"backgroundTag":null,"analyzedSha":"b5b53acc57189a4a42e44a23e149dc655c98fe82","analyzedAt":"2026-08-14T22:29:33.146Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}