diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v2/JythonTopLevelDataSetHandlerV2.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v2/JythonTopLevelDataSetHandlerV2.java
index 3103930b1fcdedf01b61d98ef00f174bc7554daf..339e56edbf53b4cc1f5e243335a6af2ec0a4c91d 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v2/JythonTopLevelDataSetHandlerV2.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v2/JythonTopLevelDataSetHandlerV2.java
@@ -232,10 +232,12 @@ public class JythonTopLevelDataSetHandlerV2<T extends DataSetInformation> extend
                                     // count
                                     // FIXME: is this safe operation (how to assure, that it won't
                                     // corrupt the recoveryMarkerFile?)
-
-                                    recoveryInfo.increaseTryCount();
-                                    recoveryInfo.setLastTry(new Date());
-                                    recoveryInfo.writeToFile(recoveryMarkerFile);
+                                    DataSetStorageRecoveryInfo rInfo =
+                                            state.getGlobalState().getStorageRecoveryManager()
+                                                    .getRecoveryFileFromMarker(recoveryMarkerFile);
+                                    rInfo.increaseTryCount();
+                                    rInfo.setLastTry(new Date());
+                                    rInfo.writeToFile(recoveryMarkerFile);
                                 }
                             }
                             return true;
@@ -335,7 +337,14 @@ public class JythonTopLevelDataSetHandlerV2<T extends DataSetInformation> extend
 
             if (recoveryStage.beforeOrEqual(RecoveryStage.PRECOMMIT))
             {
-                TechId registrationId = ((DataSetStoragePrecommitRecoveryState<T>)recoveryState).getRegistrationId();
+                TechId registrationId =
+                        ((DataSetStoragePrecommitRecoveryState<T>) recoveryState)
+                                .getRegistrationId();
+                if (registrationId == null)
+                {
+                    throw new IllegalStateException(
+                            "Recovery state cannot have null registrationId at the precommit phase");
+                }
                 entityOperationsSucceeded =
                         state.getGlobalState().getOpenBisService()
                                 .didEntityOperationsSucceed(registrationId);
@@ -377,12 +386,12 @@ public class JythonTopLevelDataSetHandlerV2<T extends DataSetInformation> extend
 
                 operationLog
                         .info("Recovery has found datasets in the AS. The registration of metadata was successful.");
-                
-                if (recoveryStage.beforeOrEqual(RecoveryStage.POST_REGISTRATION_HOOK_EXECUTED)){
+
+                if (recoveryStage.before(RecoveryStage.POST_REGISTRATION_HOOK_EXECUTED))
+                {
                     runner.postRegistration();
                 }
-                
-                
+
                 boolean success = runner.storeAfterRegistration(recoveryStage);
                 if (success)
                 {
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonDropboxRecoveryTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonDropboxRecoveryTest.java
index d0f18bd89f32544c112a38ad9857af96116cc20a..7ed7c23cfe0f3d7bbd9f69d223833e865d75a089 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonDropboxRecoveryTest.java
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonDropboxRecoveryTest.java
@@ -480,7 +480,7 @@ public class JythonDropboxRecoveryTest extends AbstractJythonDataSetHandlerTest
 
     // INFO: test with recovery from error in storage confirmed
     @Test
-    public void testRecoveryOriginalFailureAtStorageConfirmed()
+    public void testRecoveryFailureAtStorageConfirmed()
     {
         RecoveryTestCase testCase = new RecoveryTestCase("No name");
         setUpHomeDataBaseExpectations();
@@ -501,16 +501,12 @@ public class JythonDropboxRecoveryTest extends AbstractJythonDataSetHandlerTest
 
         handler.handle(markerFile);
 
-        JythonHookTestTool jythonHookTestTool =
-                JythonHookTestTool.createFromWorkingDirectory(workingDirectory);
-        // the check from the original registration
-        jythonHookTestTool.assertLogged("pre_metadata_registration");
-
-        jythonHookTestTool.assertLogged("post_metadata_registration");
+        JythonHookTestTool.assertMessagesInWorkingDirectory(workingDirectory,
+                "pre_metadata_registration", "post_metadata_registration");
 
         assertStorageProcess(atomicatOperationDetails.recordedObject(), DATA_SET_CODE,
                 "sub_data_set_1", 0);
-        
+
         setTheRecoveryInfo(testCase.recoveryRertyCount, testCase.recoveryLastTry);
 
         assertRecoveryFile(testCase.recoveryRertyCount, RecoveryInfoDateConstraint.ORIGINAL,
@@ -527,9 +523,97 @@ public class JythonDropboxRecoveryTest extends AbstractJythonDataSetHandlerTest
         // // item in store
         //
         //
-        // // the hooks after successful registration
-        // jythonHookTestTool.assertLogged("post_storage");
+        JythonHookTestTool.assertMessagesInWorkingDirectory(workingDirectory, "post_storage");
+
+    }
+
+    /**
+     * This tests the registration with adventure, where the failure and recovery happens at every
+     * possible step.
+     */
+    @Test
+    public void testRecoveryAtMultipleCheckpoints()
+    {
+        RecoveryTestCase testCase = new RecoveryTestCase("No name");
+        setUpHomeDataBaseExpectations();
+
+        createData();
+
+        Properties properties =
+                createThreadPropertiesRelativeToScriptsFolder(testCase.dropboxScriptPath,
+                        testCase.overrideProperties);
+
+        createHandler(properties, true, false);
+
+        final RecordingMatcher<ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails> atomicatOperationDetails =
+                new RecordingMatcher<ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails>();
+
+        // create expectations
+        context.checking(new MultipleErrorsExpectations(atomicatOperationDetails));
+
+        handler.handle(markerFile);
+        setTheRecoveryInfo(testCase.recoveryRertyCount, testCase.recoveryLastTry);
+
+        // now we have registered, but error was thrown from registration
+        JythonHookTestTool.assertMessagesInWorkingDirectory(workingDirectory,
+                "pre_metadata_registration");
+
+        handler.handle(markerFile);
+        setTheRecoveryInfo(testCase.recoveryRertyCount, testCase.recoveryLastTry);
 
+        // now we know we have registered, post_registration_hook executed, but storage failed.
+        JythonHookTestTool.assertMessagesInWorkingDirectory(workingDirectory,
+                "post_metadata_registration");
+
+        // so make filesystem avaiable this time
+        makeFileSystemAvailable(workingDirectory);
+
+        handler.handle(markerFile);
+        setTheRecoveryInfo(testCase.recoveryRertyCount, testCase.recoveryLastTry);
+        // now the storage has succeeded, but storage confirmation has not.
+
+        handler.handle(markerFile);
+//        setTheRecoveryInfo(testCase.recoveryRertyCount, testCase.recoveryLastTry);
+        // now the storage confirmation has succeeded
+        assertStorageProcess(atomicatOperationDetails.recordedObject(), DATA_SET_CODE,
+                "sub_data_set_1", 0);
+
+        assertNoOriginalMarkerFileExists();
+        assertNoRecoveryMarkerFile();
+
+        //
+        // // item in store
+        //
+        //
+        JythonHookTestTool.assertMessagesInWorkingDirectory(workingDirectory, "post_storage");
+
+    }
+
+    class MultipleErrorsExpectations extends AbstractExpectations
+    {
+        public MultipleErrorsExpectations(
+                final RecordingMatcher<AtomicEntityOperationDetails> atomicatOperationDetails)
+        {
+            super(atomicatOperationDetails);
+            prepareExpectations();
+        }
+
+        private void prepareExpectations()
+        {
+            initialExpectations();
+            // first try - fail at registration
+            registerDataSetsAndThrow(true);
+
+            // second handle - fail at storage
+            one(openBisService).didEntityOperationsSucceed(with(any(TechId.class)));
+            will(doAll(makeFileSystemUnavailableAction(), returnValue(true)));
+
+            // third try - fail at storage confirmation
+            setStorageConfirmed(true);
+
+            // fourth try - success
+            setStorageConfirmed(false);
+        }
     }
 
     class StorageConfirmedErrorExpectations extends AbstractExpectations
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonHookTestTool.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonHookTestTool.java
index 83576d171eb0bc466ba0ac9d03d563311452db4c..13c719575872a38864e062567c27b4ee6ad44495 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonHookTestTool.java
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonHookTestTool.java
@@ -70,22 +70,36 @@ public class JythonHookTestTool
         }
     }
 
+    /**
+     * Assert that the provided messages has been logged and nothign else. Clears the log file
+     * afterwards.
+     */
+    public static void assertMessagesInWorkingDirectory(File workingDirectory, String... messages)
+    {
+        JythonHookTestTool instance = createFromWorkingDirectory(workingDirectory);
+        for (String message : messages)
+        {
+            instance.assertLogged(message);
+        }
+        instance.assertNoMoreMessages();
+        instance.logFile.delete();
+    }
+
     /**
      * The factory method to create util
      * 
-     * @param incoming - the logical or original incoming available from the
-     *            dropbox
+     * @param incoming - the logical or original incoming available from the dropbox
      */
     public static JythonHookTestTool createFromIncoming(File incoming)
     {
         File workingDirectory;
         if (incoming.getParentFile().getParentFile().getName().equals("pre-staging"))
         {
-            //prestaging
+            // prestaging
             workingDirectory = incoming.getParentFile().getParentFile().getParentFile();
         } else
         {
-            //incoming
+            // incoming
             workingDirectory = incoming.getParentFile();
         }
         return new JythonHookTestTool(workingDirectory);
@@ -144,9 +158,6 @@ public class JythonHookTestTool
     {
         if (lineNumber < originalFileContents.length)
         {
-            for (String s: originalFileContents)
-            System.out.println(s);
-            
             throw new AssertionError("Unexpected message in jython hook test."
                     + originalFileContents[lineNumber]);
         }