Repository: jupyter-server/pycrdt (language: python)

Issue:
pycrdt throws PanicException in some cases which is unhandled
## Description

Sometimes when calling `ydoc.get_update(encoded_update)` from pycrdt, a `PanicException` is thrown which I try to handle from userland but somehow seems to escape my `try...except` block.

You can read more about this exception from `pyo3` in this GH issue: https://github.com/PyO3/pyo3/issues/3519

Specifically, the PanicException that is thrown for me when calling `ydoc.get_update(encoded_update)` has this exception message:

> called `Result::unwrap()` on an `Err` value: VarIntSizeExceeded(70)

## Reproduce

Struggling to consistently reproduce, am unsure what exact binary payloads are causing the panic.

## Expected behavior

No panics, or at least `PanicException`s I can catch.



Discussion / hints:
Thank you for opening your first issue in this project! Engagement like this is essential for open source projects! :hugs:
<br>If you haven't done so already, check out [Jupyter's Code of Conduct](https://github.com/jupyter/governance/blob/master/conduct/code_of_conduct.md). Also, please try to follow the issue template as it helps other other community members to contribute more effectively.
![welcome](https://raw.githubusercontent.com/jupyter-server/.github/master/images/welcome.jpg)
You can meet the other [Jovyans](https://jupyter.readthedocs.io/en/latest/community/content-community.html?highlight=jovyan#what-is-a-jovyan) by joining our [Discourse forum](http://discourse.jupyter.org/). There is also an intro thread there where you can stop by and say Hi! :wave:
<br>Welcome to the Jupyter community! :tada:


Fix patch:
diff --git a/src/doc.rs b/src/doc.rs
index 32284b4..b545058 100644
--- a/src/doc.rs
+++ b/src/doc.rs
@@ -1,4 +1,5 @@
 use pyo3::prelude::*;
+use pyo3::exceptions::PyValueError;
 use pyo3::types::{PyBytes, PyDict, PyLong, PyList};
 use yrs::{
     Doc as _Doc,
@@ -87,7 +88,8 @@ impl Doc {
     fn get_update(&mut self, state: &PyBytes) -> PyResult<PyObject> {
         let txn = self.doc.transact_mut();
         let state: &[u8] = FromPyObject::extract(state)?;
-        let update = txn.encode_diff_v1(&StateVector::decode_v1(&state).unwrap());
+        let Ok(state_vector) = StateVector::decode_v1(&state) else { return Err(PyValueError::new_err("Cannot decode state")) };
+        let update = txn.encode_diff_v1(&state_vector);
         drop(txn);
         let bytes: PyObject = Python::with_gil(|py| PyBytes::new(py, &update).into());
         Ok(bytes)


Test patch:
diff --git a/tests/test_doc.py b/tests/test_doc.py
index 97c2437..ef03820 100644
--- a/tests/test_doc.py
+++ b/tests/test_doc.py
@@ -203,3 +203,10 @@ def test_not_empty_update():
     events.clear()
     del text[5]
     assert events
+
+
+def test_get_update_exception():
+    doc = Doc()
+    with pytest.raises(ValueError) as excinfo:
+        doc.get_update(b"\x12")
+    assert str(excinfo.value) == "Cannot decode state"