diff --git a/src/main/java/sh/libre/scim/core/AbstractScimService.java b/src/main/java/sh/libre/scim/core/AbstractScimService.java
index 4e42351c242cb69b307ccdadea8bbd3f75cb0e45..8f92a2268147689f42cba210a4407b67fae3c328 100644
--- a/src/main/java/sh/libre/scim/core/AbstractScimService.java
+++ b/src/main/java/sh/libre/scim/core/AbstractScimService.java
@@ -35,7 +35,7 @@ public abstract class AbstractScimService<RMM extends RoleMapperModel, S extends
         this.scimClient = ScimClient.open(scimProviderConfiguration, type);
     }
 
-    public void create(RMM roleMapperModel) {
+    public void create(RMM roleMapperModel) throws ScimPropagationException {
         boolean skip = isSkip(roleMapperModel);
         if (skip)
             return;
@@ -71,7 +71,7 @@ public abstract class AbstractScimService<RMM extends RoleMapperModel, S extends
         return keycloakSession;
     }
 
-    public void replace(RMM roleMapperModel) {
+    public void replace(RMM roleMapperModel) throws ScimPropagationException {
         try {
             if (isSkip(roleMapperModel))
                 return;
@@ -84,37 +84,42 @@ public abstract class AbstractScimService<RMM extends RoleMapperModel, S extends
             LOGGER.warnf("failed to replace resource %s, scim mapping not found", getId(roleMapperModel));
         } catch (Exception e) {
             LOGGER.error(e);
+            throw new ScimPropagationException("[SCIM] Error while replacing SCIM resource", e);
         }
     }
 
     protected abstract S toScimForReplace(RMM roleMapperModel, EntityOnRemoteScimId externalId);
 
-    public void delete(KeycloakId id) {
+    public void delete(KeycloakId id) throws ScimPropagationException {
         try {
             ScimResource resource = findById(id).get();
             EntityOnRemoteScimId externalId = resource.getExternalIdAsEntityOnRemoteScimId();
             scimClient.delete(externalId);
             getScimResourceDao().delete(resource);
         } catch (NoSuchElementException e) {
-            LOGGER.warnf("Failed to delete resource %s, scim mapping not found", id);
+            throw new ScimPropagationException("Failed to delete resource %s, scim mapping not found : " + id, e);
         }
     }
 
-    public void refreshResources(SynchronizationResult syncRes) {
+    public void refreshResources(SynchronizationResult syncRes) throws ScimPropagationException {
         LOGGER.info("Refresh resources");
         getResourceStream().forEach(resource -> {
             KeycloakId id = getId(resource);
             LOGGER.infof("Reconciling local resource %s", id);
             if (!isSkipRefresh(resource)) {
                 try {
-                    findById(id).get();
-                    LOGGER.info("Replacing it");
-                    replace(resource);
-                } catch (NoSuchElementException e) {
-                    LOGGER.info("Creating it");
-                    create(resource);
+                    try {
+                        findById(id).get();
+                        LOGGER.info("Replacing it");
+                        replace(resource);
+                    } catch (NoSuchElementException e) {
+                        LOGGER.info("Creating it");
+                        create(resource);
+                    }
+                    syncRes.increaseUpdated();
+                } catch (ScimPropagationException e) {
+                    // TODO handle exception
                 }
-                syncRes.increaseUpdated();
             }
         });
     }
@@ -187,7 +192,7 @@ public abstract class AbstractScimService<RMM extends RoleMapperModel, S extends
 
     protected abstract boolean entityExists(KeycloakId keycloakId);
 
-    public void sync(SynchronizationResult syncRes) {
+    public void sync(SynchronizationResult syncRes) throws ScimPropagationException {
         if (this.scimProviderConfiguration.isSyncImport()) {
             this.importResources(syncRes);
         }
diff --git a/src/main/java/sh/libre/scim/core/ScimClient.java b/src/main/java/sh/libre/scim/core/ScimClient.java
index 35ab5620bc1fd44e08535d0afa21217059d8f7a6..22bfa0e7ec06a0472cc56be271ffc1cab0cc3132 100644
--- a/src/main/java/sh/libre/scim/core/ScimClient.java
+++ b/src/main/java/sh/libre/scim/core/ScimClient.java
@@ -19,7 +19,7 @@ import java.util.List;
 import java.util.Map;
 
 public class ScimClient<S extends ResourceNode> implements AutoCloseable {
-    private final Logger logger = Logger.getLogger(ScimClient.class);
+    private static final Logger LOGGER = Logger.getLogger(ScimClient.class);
 
     private final RetryRegistry retryRegistry;
 
@@ -83,8 +83,8 @@ public class ScimClient<S extends ResourceNode> implements AutoCloseable {
 
     private void checkResponseIsSuccess(ServerResponse<S> response) {
         if (!response.isSuccess()) {
-            logger.warn(response.getResponseBody());
-            logger.warn(response.getHttpStatus());
+            LOGGER.warn(response.getResponseBody());
+            LOGGER.warn(response.getHttpStatus());
         }
     }
 
@@ -98,7 +98,7 @@ public class ScimClient<S extends ResourceNode> implements AutoCloseable {
 
     public void replace(EntityOnRemoteScimId externalId, S scimForReplace) {
         Retry retry = retryRegistry.retry("replace-%s".formatted(externalId.asString()));
-        logger.warn(scimForReplace);
+        LOGGER.warn(scimForReplace);
         ServerResponse<S> response = retry.executeSupplier(() -> scimRequestBuilder
                 .update(getResourceClass(), getScimEndpoint(), externalId.asString())
                 .setResource(scimForReplace)
diff --git a/src/main/java/sh/libre/scim/core/ScimDispatcher.java b/src/main/java/sh/libre/scim/core/ScimDispatcher.java
index 6804c065544429c94356767ecf1821502df448da..6be68dc3d2cd3c9bf48968474e1b18e1935cc5fa 100644
--- a/src/main/java/sh/libre/scim/core/ScimDispatcher.java
+++ b/src/main/java/sh/libre/scim/core/ScimDispatcher.java
@@ -6,9 +6,10 @@ import org.keycloak.models.KeycloakSession;
 import sh.libre.scim.storage.ScimEndpointConfigurationStorageProviderFactory;
 
 import java.util.ArrayList;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Optional;
-import java.util.function.Consumer;
+import java.util.Set;
 
 /**
  * In charge of sending SCIM Request to all registered Scim endpoints.
@@ -69,38 +70,64 @@ public class ScimDispatcher {
         }
     }
 
-    public void dispatchUserModificationToAll(Consumer<UserScimService> operationToDispatch) {
+    public void dispatchUserModificationToAll(SCIMPropagationConsumer<UserScimService> operationToDispatch) {
         initializeClientsIfNeeded();
-        userScimServices.forEach(operationToDispatch);
-        logger.infof("[SCIM] User operation dispatched to %d SCIM server", userScimServices.size());
+        Set<UserScimService> servicesCorrectlyPropagated = new LinkedHashSet<>();
+        userScimServices.forEach(userScimService -> {
+            try {
+                operationToDispatch.acceptThrows(userScimService);
+                servicesCorrectlyPropagated.add(userScimService);
+            } catch (ScimPropagationException e) {
+                logAndRollback(userScimService.getConfiguration(), e);
+            }
+        });
+        // TODO we could iterate on servicesCorrectlyPropagated to undo modification
+        logger.infof("[SCIM] User operation dispatched to %d SCIM server", servicesCorrectlyPropagated.size());
     }
 
-    public void dispatchGroupModificationToAll(Consumer<GroupScimService> operationToDispatch) {
+    public void dispatchGroupModificationToAll(SCIMPropagationConsumer<GroupScimService> operationToDispatch) {
         initializeClientsIfNeeded();
-        groupScimServices.forEach(operationToDispatch);
-        logger.infof("[SCIM] Group operation dispatched to %d SCIM server", groupScimServices.size());
+        Set<GroupScimService> servicesCorrectlyPropagated = new LinkedHashSet<>();
+        groupScimServices.forEach(groupScimService -> {
+            try {
+                operationToDispatch.acceptThrows(groupScimService);
+                servicesCorrectlyPropagated.add(groupScimService);
+            } catch (ScimPropagationException e) {
+                logAndRollback(groupScimService.getConfiguration(), e);
+            }
+        });
+        // TODO we could iterate on servicesCorrectlyPropagated to undo modification
+        logger.infof("[SCIM] Group operation dispatched to %d SCIM server", servicesCorrectlyPropagated.size());
     }
 
-    public void dispatchUserModificationToOne(ComponentModel scimServerConfiguration, Consumer<UserScimService> operationToDispatch) {
+    public void dispatchUserModificationToOne(ComponentModel scimServerConfiguration, SCIMPropagationConsumer<UserScimService> operationToDispatch) {
         initializeClientsIfNeeded();
         // Scim client should already have been created
         Optional<UserScimService> matchingClient = userScimServices.stream().filter(u -> u.getConfiguration().getId().equals(scimServerConfiguration.getId())).findFirst();
         if (matchingClient.isPresent()) {
-            operationToDispatch.accept(matchingClient.get());
-            logger.infof("[SCIM] User operation dispatched to SCIM server %s", matchingClient.get().getConfiguration().getId());
+            try {
+                operationToDispatch.acceptThrows(matchingClient.get());
+                logger.infof("[SCIM] User operation dispatched to SCIM server %s", matchingClient.get().getConfiguration().getId());
+            } catch (ScimPropagationException e) {
+                logAndRollback(matchingClient.get().getConfiguration(), e);
+            }
         } else {
             logger.error("[SCIM] Could not find a Scim Client matching endpoint configuration" + scimServerConfiguration.getId());
         }
     }
 
 
-    public void dispatchGroupModificationToOne(ComponentModel scimServerConfiguration, Consumer<GroupScimService> operationToDispatch) {
+    public void dispatchGroupModificationToOne(ComponentModel scimServerConfiguration, SCIMPropagationConsumer<GroupScimService> operationToDispatch) {
         initializeClientsIfNeeded();
         // Scim client should already have been created
         Optional<GroupScimService> matchingClient = groupScimServices.stream().filter(u -> u.getConfiguration().getId().equals(scimServerConfiguration.getId())).findFirst();
         if (matchingClient.isPresent()) {
-            operationToDispatch.accept(matchingClient.get());
-            logger.infof("[SCIM] Group operation dispatched to SCIM server %s", matchingClient.get().getConfiguration().getId());
+            try {
+                operationToDispatch.acceptThrows(matchingClient.get());
+                logger.infof("[SCIM] Group operation dispatched to SCIM server %s", matchingClient.get().getConfiguration().getId());
+            } catch (ScimPropagationException e) {
+                logAndRollback(matchingClient.get().getConfiguration(), e);
+            }
         } else {
             logger.error("[SCIM] Could not find a Scim Client matching endpoint configuration" + scimServerConfiguration.getId());
         }
@@ -117,10 +144,27 @@ public class ScimDispatcher {
         userScimServices.clear();
     }
 
+    private void logAndRollback(ScrimProviderConfiguration scimServerConfiguration, ScimPropagationException e) {
+        logger.error("[SCIM] Error while propagating to SCIM endpoint " + scimServerConfiguration.getId(), e);
+        session.getTransactionManager().rollback();
+    }
+
     private void initializeClientsIfNeeded() {
         if (!clientsInitialized) {
             clientsInitialized = true;
             refreshActiveScimEndpoints();
         }
     }
+
+    /**
+     * A Consumer that throws ScimPropagationException.
+     *
+     * @param <T> An {@link AbstractScimService to call}
+     */
+    @FunctionalInterface
+    public interface SCIMPropagationConsumer<T> {
+
+        void acceptThrows(T elem) throws ScimPropagationException;
+
+    }
 }
diff --git a/src/main/java/sh/libre/scim/core/ScimPropagationException.java b/src/main/java/sh/libre/scim/core/ScimPropagationException.java
index 145c7c4c0aac9c85413c19dfc415a09b1cd35410..135b555961234788d6e3b6ede89905bfa761dcad 100644
--- a/src/main/java/sh/libre/scim/core/ScimPropagationException.java
+++ b/src/main/java/sh/libre/scim/core/ScimPropagationException.java
@@ -1,4 +1,12 @@
 package sh.libre.scim.core;
 
-public class ScimPropagationException {
+public class ScimPropagationException extends Exception {
+
+    public ScimPropagationException(String message) {
+        super(message);
+    }
+
+    public ScimPropagationException(String message, Exception e) {
+        super(message, e);
+    }
 }