diff --git a/src/OMSimulatorLib/SystemSC.cpp b/src/OMSimulatorLib/SystemSC.cpp
index 0c72d8f86..4376adf0d 100644
--- a/src/OMSimulatorLib/SystemSC.cpp
+++ b/src/OMSimulatorLib/SystemSC.cpp
@@ -881,6 +881,15 @@ oms_status_enu_t oms::SystemSC::doStepCVODE()
{
const fmi3Float64 tout = std::min(tnext, end_time);
+ // CVode rejects an interval it cannot tell apart from zero (CV_TOO_CLOSE)
+ // There is nothing left to integrate in it; assume end_time is reached.
+ if (tout - time < 2.0 * SUN_UNIT_ROUNDOFF * std::max(std::fabs(time), std::fabs(tout)))
+ {
+ logDebug("CVode: skipping degenerate interval " + std::to_string(time) + " -> " + std::to_string(tout));
+ time = end_time;
+ break;
+ }
+
logDebug("CVode: " + std::to_string(time) + " -> " + std::to_string(tout));
for (size_t j=0, k=0; j < fmus.size(); ++j)
for (size_t i=0; i < nStates[j]; ++i, ++k)
diff --git a/testsuite/tests/resources/CMakeLists.txt b/testsuite/tests/resources/CMakeLists.txt
index 11b735086..33b0927d1 100644
--- a/testsuite/tests/resources/CMakeLists.txt
+++ b/testsuite/tests/resources/CMakeLists.txt
@@ -12,6 +12,7 @@ set(OM_OMS_TESTSUITE_RESOURCES_FMUS
${CMAKE_CURRENT_SOURCE_DIR}/B
${CMAKE_CURRENT_SOURCE_DIR}/BouncingBall
${CMAKE_CURRENT_SOURCE_DIR}/BouncingBall3
+ ${CMAKE_CURRENT_SOURCE_DIR}/ClockedStepBoundary
${CMAKE_CURRENT_SOURCE_DIR}/Dahlquist
${CMAKE_CURRENT_SOURCE_DIR}/Dahlquist3
${CMAKE_CURRENT_SOURCE_DIR}/DualMassOscillator.System1
diff --git a/testsuite/tests/resources/ClockedStepBoundary.mos b/testsuite/tests/resources/ClockedStepBoundary.mos
new file mode 100644
index 000000000..ea2d6384f
--- /dev/null
+++ b/testsuite/tests/resources/ClockedStepBoundary.mos
@@ -0,0 +1,13 @@
+// Regenerates testsuite/resources/ClockedStepBoundary.
+//
+// A clocked model: Modelica.Clocked drives it from periodic clocks whose tick
+// times are computed exactly (k * period), while a master stepping the FMU
+// accumulates its own communication points. The two disagree by an ULP once the
+// accumulated end of a communication step lands just past a tick, which is what
+// the clockedStepBoundary test exercises.
+
+loadModel(Modelica, {"4.0.0"}); getErrorString();
+
+buildModelFMU(Modelica.Clocked.Examples.CascadeControlledDrive.AbsoluteClocks, version="2.0", fmuType="me", fileNamePrefix="ClockedStepBoundary", platforms={"x86_64-linux-gnu docker run multiarch/crossbuild","x86_64-w64-mingw32 docker run multiarch/crossbuild"}); getErrorString();
+
+system("zip -qd ClockedStepBoundary.fmu sources/* && unzip -o ClockedStepBoundary.fmu -d ClockedStepBoundary/");
diff --git a/testsuite/tests/resources/ClockedStepBoundary/binaries/linux64/ClockedStepBoundary.so b/testsuite/tests/resources/ClockedStepBoundary/binaries/linux64/ClockedStepBoundary.so
new file mode 100755
index 000000000..b36b89020
Binary files /dev/null and b/testsuite/tests/resources/ClockedStepBoundary/binaries/linux64/ClockedStepBoundary.so differ
diff --git a/testsuite/tests/resources/ClockedStepBoundary/documentation/index.html b/testsuite/tests/resources/ClockedStepBoundary/documentation/index.html
new file mode 100644
index 000000000..2a1397266
--- /dev/null
+++ b/testsuite/tests/resources/ClockedStepBoundary/documentation/index.html
@@ -0,0 +1,14 @@
+
+
Modelica.Clocked.Examples.CascadeControlledDrive.AbsoluteClocks
+ Drive with clocked cascade controller where all partitions are defined with exact (integer) clock that need to be compatible to each other
+ Information
+
+Cascade control drive with discrete-time controller where two
+periodic clock with absolute periods are defined and
+are associated to
+the corresponding controller partitions.
+The super-sampling factor of block "super" is derived by
+clock inference.
+
+
+ Revisions
diff --git a/testsuite/tests/resources/ClockedStepBoundary/modelDescription.xml b/testsuite/tests/resources/ClockedStepBoundary/modelDescription.xml
new file mode 100644
index 000000000..f5e3aa1c9
--- /dev/null
+++ b/testsuite/tests/resources/ClockedStepBoundary/modelDescription.xml
@@ -0,0 +1,830 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/testsuite/tests/resources/ClockedStepBoundary/resources/ClockedStepBoundary_JacA.bin b/testsuite/tests/resources/ClockedStepBoundary/resources/ClockedStepBoundary_JacA.bin
new file mode 100644
index 000000000..035462ec2
Binary files /dev/null and b/testsuite/tests/resources/ClockedStepBoundary/resources/ClockedStepBoundary_JacA.bin differ
diff --git a/testsuite/tests/simulation/CMakeLists.txt b/testsuite/tests/simulation/CMakeLists.txt
index 0815cf3b4..2e7c51615 100644
--- a/testsuite/tests/simulation/CMakeLists.txt
+++ b/testsuite/tests/simulation/CMakeLists.txt
@@ -1,4 +1,5 @@
oms_add_test(
+ clockedStepBoundary.py
DualMassOscillator1.py
DualMassOscillator2.py
exportJson1.py
diff --git a/testsuite/tests/simulation/clockedStepBoundary.py b/testsuite/tests/simulation/clockedStepBoundary.py
new file mode 100644
index 000000000..3c31829e4
--- /dev/null
+++ b/testsuite/tests/simulation/clockedStepBoundary.py
@@ -0,0 +1,44 @@
+## status: correct
+## linux: yes
+## ucrt64: no
+## win: no
+## mac: no
+## the checked-in FMU carries linux64 binaries only; rebuild it with the
+## cross-build platforms in resources/ClockedStepBoundary.mos to widen this
+
+from OMSimulator import FMU, Settings
+
+Settings.suppressPath = True
+
+# A clocked FMU integrated with CVode. Modelica.Clocked computes its tick times
+# exactly (k * period), while doStepCVODE accumulates the end of each
+# communication step. Once the accumulated end lands an ULP past a tick, the
+# interval left over after the event at that tick is smaller than CVode can
+# integrate, and CVode used to be called with it anyway - failing the whole
+# simulation with CV_TOO_CLOSE (flag -27) at t = 0.08.
+
+model = FMU('../resources/ClockedStepBoundary.fmu')
+model.mode = 'me'
+model.startTime = 0.0
+model.stopTime = 0.2
+model.tolerance = 1e-8
+model.instantiate()
+model.setSolver('cvode')
+model.setResultFile('ClockedStepBoundary_res.mat')
+model.initialize()
+model.simulate()
+model.terminate()
+model.delete()
+
+print('simulation finished', flush=True)
+
+## Result:
+## info: maximum step size for 'AbsoluteClocks.root': 0.008000
+## info: Result file: ClockedStepBoundary_res.mat (bufferSize=10)
+## info: Parameter AbsoluteClocks.fastClock.solverMethod will not be stored in the result file, because the signal type is not supported
+## info: Parameter AbsoluteClocks.slowClock.solverMethod will not be stored in the result file, because the signal type is not supported
+## info: Final Statistics for 'AbsoluteClocks.root':
+## NumSteps = 10 NumRhsEvals = 15 NumLinSolvSetups = 8
+## NumNonlinSolvIters = 14 NumNonlinSolvConvFails = 0 NumErrTestFails = 1
+## simulation finished
+## endResult