{"record":{"id":"fcc0ca1eb86af217","repo":"ruvnet/RuView","slug":"calibration-already-in-progress","errorCode":null,"errorMessage":"Calibration already in progress","messagePattern":"Calibration already in progress","errorType":"http","errorClass":"HTTPException","httpStatus":409,"severity":"warning","filePath":"archive/v1/src/api/routers/pose.py","lineNumber":333,"sourceCode":"            status_code=500,\n            detail=\"An internal error occurred. Please try again later.\"\n        )\n\n\n@router.post(\"/calibrate\")\nasync def calibrate_pose_system(\n    background_tasks: BackgroundTasks,\n    pose_service: PoseService = Depends(get_pose_service),\n    hardware_service: HardwareService = Depends(get_hardware_service),\n    current_user: Dict = Depends(require_auth)\n):\n    \"\"\"Calibrate the pose estimation system.\"\"\"\n    try:\n        logger.info(f\"Pose system calibration initiated by user: {current_user['id']}\")\n        \n        # Check if calibration is already in progress\n        if await pose_service.is_calibrating():\n            raise HTTPException(\n                status_code=409,\n                detail=\"Calibration already in progress\"\n            )\n        \n        # Start calibration process\n        calibration_id = await pose_service.start_calibration()\n        \n        # Schedule background calibration task\n        background_tasks.add_task(\n            pose_service.run_calibration,\n            calibration_id\n        )\n        \n        return {\n            \"calibration_id\": calibration_id,\n            \"status\": \"started\",\n            \"estimated_duration_minutes\": 5,\n            \"message\": \"Calibration process started\"","sourceCodeStart":315,"sourceCodeEnd":351,"githubUrl":"https://github.com/ruvnet/RuView/blob/4685618388a5e49fad5b3005806f3bdd6a7c25c3/archive/v1/src/api/routers/pose.py#L315-L351","documentation":"HTTP 409 from POST /pose/calibrate when pose_service.is_calibrating() is true — only one calibration may run at a time. The response advertises an estimated ~5-minute duration, so the conflict window is minutes, not milliseconds. The check runs before start_calibration and the handler re-raises the HTTPException unchanged.","triggerScenarios":"A second POST /pose/calibrate while a previous calibration is still running — a double-click on the calibrate button, two operators calibrating concurrently, or a client-timeout retry while the first run is in progress.","commonSituations":"UI without a disabled state during calibration; scripts auto-retrying on timeout even though the first request succeeded; an abandoned calibration run that never cleared the in-progress flag.","solutions":["Poll GET /pose/calibration/status until is_calibrating is false, then POST again","Disable the calibrate control client-side while a run is active (see exampleFix)","If status shows a stuck calibration (progress not advancing), restart the service to clear the flag"],"exampleFix":"// before\nbtn.onclick = () => api.post('/pose/calibrate');\n\n// after\nconst st = await api.get('/pose/calibration/status');\nif (!st.is_calibrating) {\n  btn.disabled = true;\n  try { await api.post('/pose/calibrate'); }\n  finally { btn.disabled = false; }\n}","handlingStrategy":"validation","validationCode":"st = (await client.get('/pose/calibration/status')).json()\nif st.get('is_calibrating'):\n    raise CalibrationInProgress(st.get('estimated_remaining_minutes'))\nawait client.post('/pose/calibrate')","typeGuard":"def calibration_is_idle(status) -> bool:\n    return isinstance(status, dict) and not status.get('is_calibrating', False)","tryCatchPattern":"resp = await client.post('/pose/calibrate')\nif resp.status_code == 409:\n    st = (await client.get('/pose/calibration/status')).json()\n    await wait_until(lambda: not get_status()['is_calibrating'], timeout=15 * 60)\n    resp = await client.post('/pose/calibrate')\nresp.raise_for_status()","preventionTips":["Disable the calibrate control while status.is_calibrating is true","Never auto-retry POST /calibrate on client timeout — the first request may have started a run","Poll /calibration/status rather than guessing when the ~5-minute run finishes"],"tags":["python","fastapi","http-409","calibration","concurrency"],"backgroundTag":null,"analyzedSha":"4685618388a5e49fad5b3005806f3bdd6a7c25c3","analyzedAt":"2026-08-16T06:09:40.886Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}