From 491a3edba05f70074d4c107b4c36a020239f375c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96rjan=20Lundberg?= Date: Fri, 21 Aug 2026 14:30:15 +0200 Subject: [PATCH] fix: don't fail the whole service list when one connection can't be decrypted decryptOrNullify(SecurityContext, ResultList) decrypted each service in a forEach with no error handling, so a single connection that could not be decrypted propagated out of the loop and failed the entire list request. Every other service disappeared from the UI along with the affected one, and because rendering the list is what failed there was no way to reach the broken service's edit form to repair its credentials. The class already declares an abstract nullifyConnection(T) hook, implemented by all eleven service resources, but nothing in the main source tree ever called it -- the only call site was a unit test. Wire it up, which is what the method's own name ("decryptOrNullify") implies was intended: catch per service, log, and return that service without a connection. The single-service GET /{id} path is left as-is, so the error is still raised where it is actionable. Fixes #31887 --- .../services/ServiceEntityResource.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/resources/services/ServiceEntityResource.java b/openmetadata-service/src/main/java/org/openmetadata/service/resources/services/ServiceEntityResource.java index 9efbec6e4d9f..696743ac131a 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/resources/services/ServiceEntityResource.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/resources/services/ServiceEntityResource.java @@ -19,6 +19,7 @@ import jakarta.ws.rs.core.SecurityContext; import jakarta.ws.rs.core.UriInfo; import lombok.Getter; +import lombok.extern.slf4j.Slf4j; import org.openmetadata.schema.ServiceConnectionEntityInterface; import org.openmetadata.schema.ServiceEntityInterface; import org.openmetadata.schema.entity.services.ServiceType; @@ -37,6 +38,7 @@ import org.openmetadata.service.secrets.masker.EntityMaskerFactory; import org.openmetadata.service.security.Authorizer; +@Slf4j public abstract class ServiceEntityResource< T extends ServiceEntityInterface, R extends ServiceEntityRepository, @@ -81,7 +83,23 @@ private Object retrieveServiceConnectionConfig(T service, boolean maskPassword) protected ResultList decryptOrNullify( SecurityContext securityContext, ResultList services) { - listOrEmpty(services.getData()).forEach(service -> decryptOrNullify(securityContext, service)); + // Degrade per service rather than failing the whole list. A single connection that + // cannot be decrypted -- most often after the Fernet key changes -- would otherwise + // propagate out of the loop and fail the request, hiding every other service and + // leaving no way to reach the affected one's edit form to repair it. + listOrEmpty(services.getData()) + .forEach( + service -> { + try { + decryptOrNullify(securityContext, service); + } catch (Exception e) { + LOG.warn( + "Failed to decrypt connection of service '{}'; returning it without one: {}", + service.getFullyQualifiedName(), + e.getMessage()); + nullifyConnection(service); + } + }); return services; }