diff --git a/petab/lint.py b/petab/lint.py
index ba9ad8f..e13f540 100644
--- a/petab/lint.py
+++ b/petab/lint.py
@@ -292,7 +292,12 @@ def check_observable_df(observable_df: pd.DataFrame) -> None:
 
         noise = getattr(row, NOISE_FORMULA)
         try:
-            sp.sympify(noise)
+            sympified_noise = sp.sympify(noise)
+            if sympified_noise is None \
+                    or (sympified_noise.is_Number
+                        and not sympified_noise.is_finite):
+                raise AssertionError(f"No or non-finite {NOISE_FORMULA} "
+                                     f"given for observable {row.Index}.")
         except sp.SympifyError as e:
             raise AssertionError(f"Cannot parse expression '{noise}' "
                                  f"for noise model for observable "

diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml
index 1c92a34..2aee552 100644
--- a/.github/workflows/ci_tests.yml
+++ b/.github/workflows/ci_tests.yml
@@ -11,7 +11,7 @@ jobs:
     strategy:
       matrix:
         platform: [windows-latest, macos-latest, ubuntu-latest]
-        python-version: [3.7, 3.8, 3.9, "3.10"]
+        python-version: ["3.7", "3.10"]
     runs-on: ${{ matrix.platform }}
 
     steps:
diff --git a/tests/test_lint.py b/tests/test_lint.py
index eccbed2..40f4c61 100644
--- a/tests/test_lint.py
+++ b/tests/test_lint.py
@@ -495,6 +495,12 @@ def test_check_observable_df():
     with pytest.raises(AssertionError):
         lint.check_observable_df(bad_observable_df)
 
+    # Check that missing noiseFormula is detected
+    bad_observable_df = observable_df.copy()
+    bad_observable_df.loc['obs1', NOISE_FORMULA] = nan
+    with pytest.raises(AssertionError):
+        lint.check_observable_df(bad_observable_df)
+
 
 def test_condition_ids_are_unique():
     condition_df = pd.DataFrame(data={

Reduce tests to min+max python?
takes quite some time to start+run all ...
tests/test_lint.py::test_check_observable_df
tests/test_lint.py::test_assert_measured_observables_present_in_model tests/test_lint.py::test_condition_table_is_parameter_free tests/test_lint.py::test_measurement_table_has_timepoint_specific_mappings tests/test_lint.py::test_observable_table_has_nontrivial_noise_formula tests/test_lint.py::test_assert_overrides_match_parameter_count tests/test_lint.py::test_assert_no_leading_trailing_whitespace tests/test_lint.py::test_assert_model_parameters_in_condition_or_parameter_table tests/test_lint.py::test_assert_noise_distributions_valid tests/test_lint.py::test_check_measurement_df tests/test_lint.py::test_check_parameter_bounds tests/test_lint.py::test_assert_parameter_prior_type_is_valid tests/test_lint.py::test_assert_parameter_prior_parameters_are_valid tests/test_lint.py::test_petablint_succeeds tests/test_lint.py::test_assert_measurement_conditions_present_in_condition_table tests/test_lint.py::test_check_condition_df tests/test_lint.py::test_check_ids tests/test_lint.py::test_check_parameter_df tests/test_lint.py::test_condition_ids_are_unique tests/test_lint.py::test_parameter_ids_are_unique