{"record":{"id":"598c008ef7df75da","repo":"pydantic/monty","slug":"current-task-is-in-unexpected-completed-state-after","errorCode":null,"errorMessage":"current task is in unexpected Completed state after resolving futures: {:?}","messagePattern":"current task is in unexpected Completed state after resolving futures: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/monty/src/bytecode/vm/async_exec.rs","lineNumber":1022,"sourceCode":"            match task.state {\n                TaskState::Failed(_) => {\n                    // Current task failed - resume with exception so it can be caught by\n                    // surrounding `try/except`.\n                    let TaskState::Failed(err) = mem::replace(&mut task.state, TaskState::Ready) else {\n                        unreachable!();\n                    };\n                    return self.resume_with_exception(err);\n                }\n                TaskState::Blocked(_) => {\n                    // Current task is still blocked on unresolved futures.\n                }\n                TaskState::Ready => {\n                    self.scheduler.remove_from_ready_queue(current_task_id);\n                    return self.run_external();\n                }\n                TaskState::Completed(_) => {\n                    // Should never have suspended if the task was completed\n                    panic!(\n                        \"current task is in unexpected Completed state after resolving futures: {:?}\",\n                        task.state\n                    );\n                }\n            }\n        }\n\n        // Current task was not able to resume, but there might be other ready tasks which can make\n        // progress\n        if let Some(next_task_id) = self.scheduler.next_ready_task() {\n            self.save_current_context();\n            self.scheduler.set_current_task(Some(next_task_id));\n            self.load_or_init_task(next_task_id)?;\n            return self.run_external();\n        }\n\n        let pending_call_ids = self.get_pending_call_ids();\n","sourceCodeStart":1004,"sourceCodeEnd":1040,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty/src/bytecode/vm/async_exec.rs#L1004-L1040","documentation":"After the host resolves pending futures, resume_with_resolved_futures re-examines the current task's state; a Completed state here means the task suspended even though it had already finished, which the scheduler never intends to do. It panics with the task's debug state. Internal scheduler invariant, not user-triggerable.","triggerScenarios":"The current task is marked Completed while parked awaiting external-future resolution — i.e. some path completed the task without removing it from the pending-await bookkeeping before resolutions were processed.","commonSituations":"Hit during development on task completion vs. suspension ordering in async_exec.rs.","solutions":["Ensure every path that completes a task also removes it from pending resolution delivery","Check handle_task_completion's waiter-handoff branch does not leave the completed task as current","Assert the task is not Completed before registering it for future resolutions","Report with a repro if triggered by plain asyncio-style code"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Complete and dequeue a task in one step, never leaving it current-and-completed","Check pending-resolution registration happens before any completion path","Re-run the scheduler's resume tests after completion-path changes"],"tags":["async","internal-panic","scheduler"],"backgroundTag":"internal-invariant-violation","analyzedSha":"adc986b362e3961f407868cb118a99fe831b9e61","analyzedAt":"2026-09-13T19:19:18.698Z","contentChangedAt":"2026-09-13T19:19:18.698Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}