diff --git a/src/ExceptionHandlingDecorator.cc b/src/ExceptionHandlingDecorator.cc
index d127e93d90a2f26c60d414395efa4ee96d39e590..cc09ec7a29bd6566e0eb2b15c2cd19fed3f62744 100644
--- a/src/ExceptionHandlingDecorator.cc
+++ b/src/ExceptionHandlingDecorator.cc
@@ -101,7 +101,7 @@ namespace ChimeraTK {
 
   template<typename UserType>
   void ExceptionHandlingDecorator<UserType>::doPreWrite() {
-    /* Copy data to the recoveryAcessor before perfroming the write.
+    /* For writable accessors, copy data to the recoveryAcessor before perfroming the write.
      * Otherwise, the decorated accessor may have swapped the data out of the user buffer already.
      * This obtains a shared lock from the DeviceModule, hence, the regular writing happeniin here
      * can be performed in shared mode of the mutex and accessors are not blocking each other.
@@ -111,9 +111,14 @@ namespace ChimeraTK {
     {
       auto lock{dm.getRecoverySharedLock()};
 
-      // Access to _recoveryAccessor is only possible channel-wise
-      for(unsigned int ch=0; ch<_recoveryAccessor->getNumberOfChannels(); ++ch){
-        _recoveryAccessor->accessChannel(ch) = buffer_2D[ch];
+      if(_recoveryAccessor != nullptr){
+        // Access to _recoveryAccessor is only possible channel-wise
+        for(unsigned int ch=0; ch<_recoveryAccessor->getNumberOfChannels(); ++ch){
+          _recoveryAccessor->accessChannel(ch) = buffer_2D[ch];
+        }
+      }
+      else{
+        throw ChimeraTK::logic_error("ChimeraTK::ExceptionhandlingDecorator: Calling write() on a non-writeable accessor is not supported ");
       }
     }
     // Now delegate call to the generic decorator, which swaps the buffer
diff --git a/tests/executables_src/testProcessVariableRecovery.cc b/tests/executables_src/testProcessVariableRecovery.cc
index be606c19f23a471fb4b24b4f2a5706573e59ccf1..1b5c5612d8daf649cb2b2434835c22f21f901fa8 100644
--- a/tests/executables_src/testProcessVariableRecovery.cc
+++ b/tests/executables_src/testProcessVariableRecovery.cc
@@ -12,6 +12,8 @@
 #include "ApplicationModule.h"
 #include "ArrayAccessor.h"
 
+#include <regex>
+
 using namespace boost::unit_test_framework;
 namespace ctk = ChimeraTK;
 
@@ -52,8 +54,76 @@ struct TestApplication : public ctk::Application {
   TestModule module{this, "TEST", "The test module"};
 };
 
+/* Test application for the specific case of wrinting to a read-only
+ * accessor. Provides an input to an ApplicationModule from a read-only
+ * accessor of the device. For the test, the accessor must not be routed
+ * through the control system, the illegal write would be catched by the
+ * ControlSystemAdapter, not by the ExceptionHandlingDecorator under test here.
+ */
+struct ReadOnlyTestApplication : public ctk::Application {
+  ReadOnlyTestApplication() : Application("ReadOnlytestApp") {}
+  ~ReadOnlyTestApplication(){ shutdown(); }
+
+  void defineConnections() {
+    dev["TEST"]("FROM_DEV_SCALAR2") >> module("FROM_DEV_SCALAR2");
+    findTag("CS").connectTo(cs);
+  }
+
+  ctk::ControlSystemModule cs;
+  ctk::DeviceModule dev{this, deviceCDD};
+
+  struct TestModule : public ctk::ApplicationModule {
+    using ctk::ApplicationModule::ApplicationModule;
+
+    ctk::ScalarPushInput<int>     start{this, "startTest", "", "This has to be written once, before writing to the device", {"CS"}};
+    ctk::ScalarPollInput<int32_t> scalarROInput{this, "FROM_DEV_SCALAR2", "", "Here I read from a scalar RO-register"};
+
+    void mainLoop() override {
+
+      // Just to have a blocking read, gives the test
+      // time to dumpConnections and explicitly trigger
+      // before terminating.
+      start.read();
+
+      scalarROInput = 42;
+      try{
+        scalarROInput.write();
+        BOOST_CHECK_MESSAGE(false,
+          "ReadOnlyTestApplication: Calling write() on input to read-only device register did not throw.");
+      }
+      catch(ChimeraTK::logic_error &e){
+
+        const std::string exMsg{e.what()};
+        std::regex exceptionHandlingRegex{"^ChimeraTK::ExceptionhandlingDecorator:*"};
+        std::smatch exMatch;
+
+        BOOST_CHECK(std::regex_search(exMsg, exMatch, exceptionHandlingRegex));
+      }
+    }
+
+  } module{this, "READ_ONLY_TEST", "The test module"};
+};
+
 /*********************************************************************************************************************/
 
+BOOST_AUTO_TEST_CASE(testWriteToReadOnly){
+  std::cout << "testWriteToReadOnly" << std::endl;
+
+  ReadOnlyTestApplication app;
+
+  ctk::TestFacility test;
+
+  app.run();
+  app.dumpConnections();
+
+  // Should trigger the blocking read in ReadOnlyTestApplication's
+  // ApplicationModule. It then writes to a read-only register of the device,
+  // which should throw. Check is done in the module's mainLoop. We can not check
+  // here, as the exception gets thrown in the thread of the module.
+  test.writeScalar("/READ_ONLY_TEST/startTest", 1);
+}
+
+
 BOOST_AUTO_TEST_CASE(testProcessVariableRecovery) {
   std::cout << "testProcessVariableRecovery" << std::endl;
   TestApplication app;