{"record":{"id":"ff97c0d6598b9c50","repo":"zed-industries/zed","slug":"could-not-find-call-to-decline","errorCode":null,"errorMessage":"could not find call to decline","messagePattern":"could not find call to decline","errorType":"validation","errorClass":"Error::Internal","httpStatus":null,"severity":"warning","filePath":"crates/collab/src/db/queries/rooms.rs","lineNumber":242,"sourceCode":"        expected_room_id: Option<RoomId>,\n        user_id: UserId,\n    ) -> Result<Option<TransactionGuard<proto::Room>>> {\n        self.optional_room_transaction(|tx| async move {\n            let mut filter = Condition::all()\n                .add(room_participant::Column::UserId.eq(user_id))\n                .add(room_participant::Column::AnsweringConnectionId.is_null());\n            if let Some(room_id) = expected_room_id {\n                filter = filter.add(room_participant::Column::RoomId.eq(room_id));\n            }\n            let participant = room_participant::Entity::find()\n                .filter(filter)\n                .one(&*tx)\n                .await?;\n\n            let participant = if let Some(participant) = participant {\n                participant\n            } else if expected_room_id.is_some() {\n                return Err(anyhow!(\"could not find call to decline\"))?;\n            } else {\n                return Ok(None);\n            };\n\n            let room_id = participant.room_id;\n            room_participant::Entity::delete(participant.into_active_model())\n                .exec(&*tx)\n                .await?;\n\n            let room = self.get_room(room_id, &tx).await?;\n            Ok(Some((room_id, room)))\n        })\n        .await\n    }\n\n    pub async fn cancel_call(\n        &self,\n        room_id: RoomId,","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/zed-industries/zed/blob/bc538def4545534201bbfcac4e95ac34ea6501b6/crates/collab/src/db/queries/rooms.rs#L224-L260","documentation":"Thrown by decline_call when expected_room_id is Some but no pending room_participant row matches the filter (called user, unanswered, null answering_connection, matching room). The Some(room_id) argument is an assertion that a specific ring exists; when the row is gone the server refuses instead of silently succeeding. With expected_room_id None the same lookup returns Ok(None) instead of erroring.","triggerScenarios":"Declining a ring that the caller already cancelled (CancelCall deleted the row); declining after the ring timed out and was cleaned up; passing the wrong room_id from a stale incoming-call notification; double-clicking decline so the second request finds nothing.","commonSituations":"Race between the caller cancelling and the callee declining; UI showing a stale ring notification after the room state changed; automated tests declining fabricated calls.","solutions":["Pass expected_room_id: None when you want a graceful no-op if the ring already vanished; keep Some(room_id) only when your UI is certain the ring is live","Drop the incoming-call notification from the UI as soon as a cancel/room-updated event arrives so decline cannot be sent for a dead ring","Treat this error as 'call already gone' and simply close the notification, not as a failure"],"exampleFix":"// before\nclient.decline_call(Some(room_id)).await?;\n\n// after (tolerate vanished rings)\nmatch client.decline_call(Some(room_id)).await {\n    Ok(_) => {}\n    Err(err) if err.to_string().contains(\"could not find call to decline\") => {\n        // ring was cancelled or expired; nothing to do\n    }\n    Err(err) => return Err(err),\n}","handlingStrategy":"try-catch","validationCode":"// Only decline rings the client still believes are live.\nif let Some(ring) = self.incoming_calls.get(&room_id) {\n    client.decline_call(Some(room_id)).await?;\n    self.incoming_calls.remove(&room_id);\n} else {\n    log::debug!(\"no live ring for room {room_id}; skipping decline\");\n}","typeGuard":null,"tryCatchPattern":"match client.decline_call(Some(room_id)).await {\n    Ok(_) => {}\n    Err(err) if err.to_string().contains(\"could not find call to decline\") => {\n        self.incoming_calls.remove(&room_id); // ring vanished; benign\n    }\n    Err(err) => return Err(err),\n}","preventionTips":["Pass Some(room_id) only for rings currently shown as active","Remove incoming-call notifications as soon as cancel/room-updated events arrive","Idempotently handle double-decline in the UI (disable the button after first tap)"],"tags":["voice-calls","rooms","race-condition","decline","server"],"backgroundTag":null,"analyzedSha":"bc538def4545534201bbfcac4e95ac34ea6501b6","analyzedAt":"2026-08-16T07:30:46.435Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}