diff --git a/grpc4bmi/bmi_client_apptainer.py b/grpc4bmi/bmi_client_apptainer.py
index 100a85b..a4169e2 100644
--- a/grpc4bmi/bmi_client_apptainer.py
+++ b/grpc4bmi/bmi_client_apptainer.py
@@ -8,7 +8,7 @@ from typing import Iterable
 
 from packaging.specifiers import SpecifierSet
 from packaging.version import Version
-from typeguard import check_argument_types, qualified_name
+from typeguard import typechecked
 
 from grpc4bmi.bmi_grpc_client import BmiClient
 from grpc4bmi.exceptions import ApptainerVersionException, DeadContainerException
@@ -194,13 +194,13 @@ class BmiClientApptainer(BmiClient):
 
     """
 
+    @typechecked
     def __init__(self, image: str, work_dir: str, input_dirs: Iterable[str] = tuple(), delay=0, timeout=None,
                  capture_logs=True,
                  ):
-        assert check_argument_types()
         if type(input_dirs) == str:
             msg = f'type of argument "input_dirs" must be collections.abc.Iterable; ' \
-                  f'got {qualified_name(input_dirs)} instead'
+                  f'got {type(input_dirs)} instead'
             raise TypeError(msg)
         check_apptainer_version()
         host = 'localhost'
diff --git a/grpc4bmi/bmi_client_docker.py b/grpc4bmi/bmi_client_docker.py
index d14fe67..328400a 100644
--- a/grpc4bmi/bmi_client_docker.py
+++ b/grpc4bmi/bmi_client_docker.py
@@ -5,7 +5,7 @@ from typing import Iterable
 
 import docker
 from docker.models.containers import Container
-from typeguard import check_argument_types, qualified_name
+from typeguard import typechecked
 
 from grpc4bmi.bmi_grpc_client import BmiClient
 from grpc4bmi.exceptions import DeadContainerException
@@ -58,14 +58,14 @@ class BmiClientDocker(BmiClient):
     See :py:class:`grpc4bmi.bmi_client_apptainer.BmiClientApptainer` for examples using `input_dirs` and `work_dir`.
     """
 
+    @typechecked
     def __init__(self, image: str, work_dir: str, image_port=50051, host=None,
                  input_dirs: Iterable[str] = tuple(),
                  user=os.getuid(), remove=False, delay=5,
                  timeout=None):
-        assert check_argument_types()
         if type(input_dirs) == str:
             msg = f'type of argument "input_dirs" must be collections.abc.Iterable; ' \
-                  f'got {qualified_name(input_dirs)} instead'
+                  f'got {type(input_dirs)} instead'
             raise TypeError(msg)
         port = BmiClient.get_unique_port()
         client = docker.from_env()
diff --git a/grpc4bmi/bmi_client_singularity.py b/grpc4bmi/bmi_client_singularity.py
index 3a49871..f2f1e4a 100644
--- a/grpc4bmi/bmi_client_singularity.py
+++ b/grpc4bmi/bmi_client_singularity.py
@@ -8,7 +8,7 @@ from typing import Iterable
 
 from packaging.specifiers import SpecifierSet
 from packaging.version import Version
-from typeguard import check_argument_types, qualified_name
+from typeguard import typechecked
 
 from grpc4bmi.bmi_grpc_client import BmiClient
 from grpc4bmi.exceptions import ApptainerVersionException, DeadContainerException, SingularityVersionException
@@ -197,13 +197,13 @@ class BmiClientSingularity(BmiClient):
 
     """
 
+    @typechecked
     def __init__(self, image: str, work_dir: str, input_dirs: Iterable[str] = tuple(), delay=0, timeout=None,
                  capture_logs=True,
                  ):
-        assert check_argument_types()
         if type(input_dirs) == str:
             msg = f'type of argument "input_dirs" must be collections.abc.Iterable; ' \
-                  f'got {qualified_name(input_dirs)} instead'
+                  f'got {type(input_dirs)} instead'
             raise TypeError(msg)
         check_singularity_version()
         host = 'localhost'
diff --git a/grpc4bmi/bmi_grpc_client.py b/grpc4bmi/bmi_grpc_client.py
index cacfa34..2db4cfe 100644
--- a/grpc4bmi/bmi_grpc_client.py
+++ b/grpc4bmi/bmi_grpc_client.py
@@ -9,7 +9,7 @@ import numpy as np
 from bmipy import Bmi
 import grpc
 import numpy
-from typeguard import check_argument_types
+from typeguard import typechecked
 
 from grpc_status import rpc_status
 from google.rpc import error_details_pb2
@@ -94,8 +94,8 @@ class BmiClient(Bmi):
             s.bind(("" if host is None else host, 0))
             return int(s.getsockname()[1])
 
+    @typechecked
     def initialize(self, filename: Optional[str]):
-        assert check_argument_types()
         fname = "" if filename is None else filename
         try:
             return self.stub.initialize(bmi_pb2.InitializeRequest(config_file=fname))
diff --git a/pyproject.toml b/pyproject.toml
index 4d4d9e8..de9cf52 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -28,7 +28,7 @@ dependencies = [
     "grpcio-reflection",
     "grpcio-status",
     "googleapis-common-protos>=1.5.5",
-    "protobuf",
+    "protobuf>=4,<5",
     "numpy",
     "docker",
     "bmipy",

diff --git a/test/test_apptainer.py b/test/test_apptainer.py
index 8dd570b..cd5ea5e 100644
--- a/test/test_apptainer.py
+++ b/test/test_apptainer.py
@@ -1,7 +1,8 @@
 import os
-from typing import Type, Union
+from typing import Type
 
 import pytest
+from typeguard import TypeCheckError
 
 from grpc4bmi.bmi_client_apptainer import SUPPORTED_APPTAINER_VERSIONS, BmiClientApptainer, check_apptainer_version_string
 from grpc4bmi.exceptions import ApptainerVersionException, DeadContainerException
@@ -64,17 +65,17 @@ class TestBmiClientApptainerBadDays:
             BmiClientApptainer(image=IMAGE_NAME, input_dirs=(some_dir,), work_dir=some_dir)
 
     def test_workdir_as_number(self):
-        with pytest.raises(TypeError, match='must be str'):
+        with pytest.raises(TypeCheckError, match='is not an instance of str'):
             BmiClientApptainer(image=IMAGE_NAME, work_dir=42)
 
     def test_inputdirs_as_str(self, tmp_path):
         some_dir = str(tmp_path)
-        with pytest.raises(TypeError, match='must be collections.abc.Iterable; got str instead'):
+        with pytest.raises(TypeError, match=' must be collections.abc.Iterable'):
             BmiClientApptainer(image=IMAGE_NAME, input_dirs='old type', work_dir=some_dir)
 
     def test_inputdirs_as_number(self, tmp_path):
         some_dir = str(tmp_path)
-        with pytest.raises(TypeError, match='must be collections.abc.Iterable; got int instead'):
+        with pytest.raises(TypeCheckError, match='is not an instance of collections.abc.Iterable'):
             BmiClientApptainer(image=IMAGE_NAME, input_dirs=42, work_dir=some_dir)
 
 
diff --git a/test/test_client.py b/test/test_client.py
index e1c643a..cf00c3b 100644
--- a/test/test_client.py
+++ b/test/test_client.py
@@ -9,6 +9,7 @@ from google.protobuf import any_pb2
 from google.rpc import error_details_pb2, status_pb2, code_pb2
 from grpc_status import rpc_status
 from heat import BmiHeat
+from typeguard import TypeCheckError
 
 from grpc4bmi.bmi_grpc_server import BmiServer
 from grpc4bmi.bmi_grpc_client import BmiClient, RemoteException, handle_error
@@ -108,7 +109,7 @@ def test_initialize():
 def test_initialize_with_nonstring():
     client, local = make_bmi_classes(False)
     assert client is not None
-    with pytest.raises(TypeError, match='got int instead'):
+    with pytest.raises(TypeCheckError, match='did not match any element in the union'):
         client.initialize(42)
     client.finalize()
     del client
diff --git a/test/test_docker.py b/test/test_docker.py
index 7b8fc65..812ec21 100644
--- a/test/test_docker.py
+++ b/test/test_docker.py
@@ -3,6 +3,7 @@ from io import BytesIO
 import docker
 import numpy as np
 import pytest
+from typeguard import TypeCheckError
 
 from grpc4bmi.bmi_client_docker import BmiClientDocker
 from grpc4bmi.exceptions import DeadContainerException
@@ -102,17 +103,17 @@ class TestBmiClientDocker:
             BmiClientDocker(image=walrus_docker_image, image_port=55555, input_dirs=(some_dir,), work_dir=some_dir)
 
     def test_workdir_as_number(self):
-        with pytest.raises(TypeError, match='must be str'):
+        with pytest.raises(TypeCheckError, match='is not an instance of str'):
             BmiClientDocker(image=walrus_docker_image, work_dir=42)
 
     def test_inputdirs_as_str(self, tmp_path):
         some_dir = str(tmp_path)
-        with pytest.raises(TypeError, match='must be collections.abc.Iterable; got str instead'):
+        with pytest.raises(TypeError, match='must be collections.abc.Iterable'):
             BmiClientDocker(image=walrus_docker_image, input_dirs='old type', work_dir=some_dir)
 
     def test_inputdirs_as_number(self, tmp_path):
         some_dir = str(tmp_path)
-        with pytest.raises(TypeError, match='must be collections.abc.Iterable; got int instead'):
+        with pytest.raises(TypeCheckError, match='is not an instance of collections.abc.Iterable'):
             BmiClientDocker(image=walrus_docker_image, input_dirs=42, work_dir=some_dir)
 
     def test_logs(self, walrus_model, capfd):
diff --git a/test/test_singularity.py b/test/test_singularity.py
index 41e4265..1f9d8b1 100644
--- a/test/test_singularity.py
+++ b/test/test_singularity.py
@@ -10,6 +10,7 @@ from grpc import RpcError
 from nbconvert.preprocessors import ExecutePreprocessor
 from nbformat.v4 import new_notebook, new_code_cell
 import numpy as np
+from typeguard import TypeCheckError
 
 from grpc4bmi.bmi_client_singularity import SUPPORTED_APPTAINER_VERSIONS, SUPPORTED_SINGULARITY_VERSIONS, BmiClientSingularity, check_singularity_version_string
 from grpc4bmi.exceptions import ApptainerVersionException, DeadContainerException, SingularityVersionException
@@ -167,17 +168,17 @@ class TestBmiClientSingularity:
         assert len(model.get_value('Q', np.zeros(1,))) == 1
 
     def test_workdir_as_number(self):
-        with pytest.raises(TypeError, match='must be str'):
+        with pytest.raises(TypeCheckError, match='is not an instance of str'):
             BmiClientSingularity(image=IMAGE_NAME, work_dir=42)
 
     def test_inputdirs_as_str(self, tmp_path):
         some_dir = str(tmp_path)
-        with pytest.raises(TypeError, match='must be collections.abc.Iterable; got str instead'):
+        with pytest.raises(TypeError, match='must be collections.abc.Iterable'):
             BmiClientSingularity(image=IMAGE_NAME, input_dirs='old type', work_dir=some_dir)
 
     def test_inputdirs_as_number(self, tmp_path):
         some_dir = str(tmp_path)
-        with pytest.raises(TypeError, match='must be collections.abc.Iterable; got int instead'):
+        with pytest.raises(TypeCheckError, match='is not an instance of collections.abc.Iterable'):
             BmiClientSingularity(image=IMAGE_NAME, input_dirs=42, work_dir=some_dir)
 
 

Incompatibility with typeguard 3
Seems typeguard 3 was released which deprecates functions used in this repo. We should use the new way or pin typeguard to <3.

For example in ewatercycle test we got:

````
________________ ERROR collecting tests/forcing/test_default.py ________________
16
ImportError while importing test module '/home/runner/work/ewatercycle/ewatercycle/tests/forcing/test_default.py'.
17
Hint: make sure your test modules/packages have valid Python names.
18
Traceback:
19
/usr/share/miniconda3/envs/ewatercycle/lib/python3.9/importlib/__init__.py:127: in import_module
20
    return _bootstrap._gcd_import(name[level:], package, level)
21
tests/forcing/test_default.py:5: in <module>
22
    from ewatercycle.forcing import (
23
src/ewatercycle/forcing/__init__.py:8: in <module>
24
    from . import _hype, _lisflood, _marrmot, _pcrglobwb, _wflow
25
src/ewatercycle/forcing/_lisflood.py:18: in <module>
26
    from ._lisvap import create_lisvap_config, lisvap
27
src/ewatercycle/forcing/_lisvap.py:29: in <module>
28
    from ewatercycle.container import ContainerEngine
29
src/ewatercycle/container.py:7: in <module>
30
    from grpc4bmi.bmi_client_docker import BmiClientDocker
31
/usr/share/miniconda3/envs/ewatercycle/lib/python3.9/site-packages/grpc4bmi/bmi_client_docker.py:8: in <module>
32
    from typeguard import check_argument_types, qualified_name
33
E   ImportError: cannot import name 'check_argument_types' from 'typeguard' (/usr/share/miniconda3/envs/ewatercycle/lib/python3.9/site-packages/typeguard/__init__.py)

```

Found while running bmi2 branch.
test/test_apptainer.py::Test_check_apptainer_version_string::test_ok[apptainer test/test_apptainer.py::Test_check_apptainer_version_string::test_too_old[apptainer test/test_apptainer.py::TestBmiClientApptainerBadDays::test_workdir_as_number test/test_apptainer.py::TestBmiClientApptainerBadDays::test_inputdirs_as_str test/test_apptainer.py::TestBmiClientApptainerBadDays::test_inputdirs_as_number test/test_client.py::test_server_start test/test_client.py::test_component_name test/test_client.py::test_input_item_count test/test_client.py::test_output_item_count test/test_client.py::test_input_var_names test/test_client.py::test_output_var_names test/test_client.py::test_initialize test/test_client.py::test_initialize_with_nonstring test/test_client.py::test_update test/test_client.py::test_update_until test/test_client.py::test_get_time_unit test/test_client.py::test_get_time_step test/test_client.py::test_get_current_time test/test_client.py::test_get_updated_time test/test_client.py::test_get_start_end_time test/test_client.py::test_get_var_grid test/test_client.py::test_get_var_type test/test_client.py::test_get_var_units test/test_client.py::test_get_var_nbytes test/test_client.py::test_get_var_location test/test_client.py::test_get_var_value test/test_client.py::test_get_value_ptr test/test_client.py::test_get_vals_indices test/test_client.py::test_set_var_value test/test_client.py::test_set_values_indices test/test_client.py::test_get_grid_size test/test_client.py::test_get_grid_rank test/test_client.py::test_get_grid_type test/test_client.py::test_get_grid_shape test/test_client.py::test_get_grid_spacing test/test_client.py::test_get_grid_origin test/test_client.py::test_method_exception[initialize-client_request0] test/test_client.py::test_method_exception[update-client_request1] test/test_client.py::test_method_exception[update_until-client_request2] test/test_client.py::test_method_exception[finalize-client_request3] test/test_client.py::test_method_exception[get_component_name-client_request4] test/test_client.py::test_method_exception[get_input_item_count-client_request5] test/test_client.py::test_method_exception[get_output_item_count-client_request6] test/test_client.py::test_method_exception[get_input_var_names-client_request7] test/test_client.py::test_method_exception[get_output_var_names-client_request8] test/test_client.py::test_method_exception[get_time_units-client_request9] test/test_client.py::test_method_exception[get_time_step-client_request10] test/test_client.py::test_method_exception[get_current_time-client_request11] test/test_client.py::test_method_exception[get_start_time-client_request12] test/test_client.py::test_method_exception[get_end_time-client_request13] test/test_client.py::test_method_exception[get_var_grid-client_request14] test/test_client.py::test_method_exception[get_var_type-client_request15] test/test_client.py::test_method_exception[get_var_itemsize-client_request16] test/test_client.py::test_method_exception[get_var_units-client_request17] test/test_client.py::test_method_exception[get_var_nbytes-client_request18] test/test_client.py::test_method_exception[get_var_location-client_request19] test/test_client.py::test_method_exception[get_value-client_request20] test/test_client.py::test_method_exception[get_value_at_indices-client_request21] test/test_client.py::test_method_exception[set_value-client_request22] test/test_client.py::test_method_exception[set_value_at_indices-client_request23] test/test_client.py::test_method_exception[get_grid_size-client_request24] test/test_client.py::test_method_exception[get_grid_type-client_request25] test/test_client.py::test_method_exception[get_grid_rank-client_request26] test/test_client.py::test_method_exception[get_grid_x-client_request27] test/test_client.py::test_method_exception[get_grid_y-client_request28] test/test_client.py::test_method_exception[get_grid_z-client_request29] test/test_client.py::test_method_exception[get_grid_shape-client_request30] test/test_client.py::test_method_exception[get_grid_spacing-client_request31] test/test_client.py::test_method_exception[get_grid_origin-client_request32] test/test_client.py::test_method_exception[get_grid_node_count-client_request33] test/test_client.py::test_method_exception[get_grid_edge_count-client_request34] test/test_client.py::test_method_exception[get_grid_face_count-client_request35] test/test_client.py::test_method_exception[get_grid_edge_nodes-client_request36] test/test_client.py::test_method_exception[get_grid_face_nodes-client_request37] test/test_client.py::test_method_exception[get_grid_face_edges-client_request38] test/test_client.py::test_method_exception[get_grid_nodes_per_face-client_request39] test/test_client.py::TestUniRectGridModel::test_grid_type test/test_client.py::TestUniRectGridModel::test_grid_size test/test_client.py::TestUniRectGridModel::test_grid_rank test/test_client.py::TestUniRectGridModel::test_grid_shape test/test_client.py::TestUniRectGridModel::test_grid_origin test/test_client.py::TestUniRectGridModel::test_grid_spacing test/test_client.py::TestRect3DGridModel::test_grid_size test/test_client.py::TestRect3DGridModel::test_grid_rank test/test_client.py::TestRect3DGridModel::test_grid_x test/test_client.py::TestRect3DGridModel::test_grid_y test/test_client.py::TestRect3DGridModel::test_grid_z test/test_client.py::TestRect2DGridModel::test_grid_size test/test_client.py::TestRect2DGridModel::test_grid_rank test/test_client.py::TestRect2DGridModel::test_grid_x test/test_client.py::TestRect2DGridModel::test_grid_y test/test_client.py::TestRect2DGridModel::test_grid_z test/test_client.py::TestStructured3DQuadrilateralsGridModel::test_grid_size test/test_client.py::TestStructured3DQuadrilateralsGridModel::test_grid_rank test/test_client.py::TestStructured3DQuadrilateralsGridModel::test_grid_shape test/test_client.py::TestStructured3DQuadrilateralsGridModel::test_grid_x test/test_client.py::TestStructured3DQuadrilateralsGridModel::test_grid_y test/test_client.py::TestStructured3DQuadrilateralsGridModel::test_grid_z test/test_client.py::TestStructured2DQuadrilateralsGridModel::test_grid_size test/test_client.py::TestStructured2DQuadrilateralsGridModel::test_grid_rank test/test_client.py::TestStructured2DQuadrilateralsGridModel::test_grid_shape test/test_client.py::TestStructured2DQuadrilateralsGridModel::test_grid_x test/test_client.py::TestStructured2DQuadrilateralsGridModel::test_grid_y test/test_client.py::TestStructured2DQuadrilateralsGridModel::test_grid_z test/test_client.py::TestUnstructuredGridBmiModel::test_get_grid_shape test/test_client.py::TestUnstructuredGridBmiModel::test_grid_size test/test_client.py::TestUnstructuredGridBmiModel::test_grid_rank test/test_client.py::TestUnstructuredGridBmiModel::test_get_grid_node_count test/test_client.py::TestUnstructuredGridBmiModel::test_get_grid_edge_count test/test_client.py::TestUnstructuredGridBmiModel::test_get_grid_face_count test/test_client.py::TestUnstructuredGridBmiModel::test_get_grid_edge_nodes test/test_client.py::TestUnstructuredGridBmiModel::test_grid_face_nodes test/test_client.py::TestUnstructuredGridBmiModel::test_grid_face_edges test/test_client.py::TestUnstructuredGridBmiModel::test_grid_nodes_per_face test/test_client.py::TestUnstructuredGridBmiModel::test_grid_x test/test_client.py::TestUnstructuredGridBmiModel::test_grid_y test/test_client.py::TestUnstructuredGridBmiModel::test_grid_z test/test_client.py::TestFloat32Model::test_get_value test/test_client.py::TestFloat32Model::test_get_value_at_indices test/test_client.py::TestFloat32Model::test_set_value test/test_client.py::TestFloat32Model::test_set_value_at_indices test/test_client.py::TestInt32Model::test_get_value test/test_client.py::TestInt32Model::test_get_value_at_indices test/test_client.py::TestInt32Model::test_set_value test/test_client.py::TestInt32Model::test_set_value_at_indices test/test_client.py::TestBooleanModel::test_get_value test/test_client.py::TestBooleanModel::test_get_value_at_indices test/test_client.py::TestBooleanModel::test_set_value test/test_client.py::TestBooleanModel::test_set_value_at_indices test/test_client.py::test_handle_error_with_stacktrace test/test_client.py::test_handle_error_without_stacktrace test/test_client.py::test_handle_error_without_status test/test_client.py::TestModelWithItemSizeZeroAndVarTypeFloat32::test_get_var_itemsize test/test_client.py::TestModelWithItemSizeZeroAndUnknownVarType::test_get_var_itemsize test/test_docker.py::TestBmiClientDocker::test_workdir_as_number test/test_docker.py::TestBmiClientDocker::test_inputdirs_as_str test/test_docker.py::TestBmiClientDocker::test_inputdirs_as_number test/test_singularity.py::TestBmiClientSingularity::test_workdir_as_number test/test_singularity.py::TestBmiClientSingularity::test_inputdirs_as_str test/test_singularity.py::TestBmiClientSingularity::test_inputdirs_as_number test/test_singularity.py::Test_check_singularity_version_string::test_ok[singularity test/test_singularity.py::Test_check_singularity_version_string::test_ok[apptainer test/test_singularity.py::Test_check_singularity_version_string::test_too_old[singularity test/test_singularity.py::Test_check_singularity_version_string::test_too_old[apptainer