You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polaris.apache.org by di...@apache.org on 2026/06/10 15:26:27 UTC
(polaris) branch main updated: Print exception stack trace when admin purge command fails (#4632)
This is an automated email from the ASF dual-hosted git repository.
dimas-b pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/polaris.git
The following commit(s) were added to refs/heads/main by this push:
new ef9fb74cbd Print exception stack trace when admin purge command fails (#4632)
ef9fb74cbd is described below
commit ef9fb74cbd25bafda2bf39c8f4c38f981028135e
Author: vignesh_A <16...@users.noreply.github.com>
AuthorDate: Wed Jun 10 20:56:22 2026 +0530
Print exception stack trace when admin purge command fails (#4632)
---
CHANGELOG.md | 1 +
.../org/apache/polaris/admintool/PurgeCommand.java | 1 +
.../apache/polaris/admintool/PurgeCommandTest.java | 99 ++++++++++++++++++++++
3 files changed, 101 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7e0c6d528c..0a75937528 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -62,6 +62,7 @@ request adding CHANGELOG notes for breaking (!) changes and possibly other secti
### Fixes
- `RateLimiterFilter` now returns an Iceberg-compatible `ErrorResponse` JSON body on HTTP 429, with `Content-Type: application/json`. Previously the body was empty, causing Iceberg REST clients to surface an opaque error.
+- The admin tool `purge` command now prints the underlying exception stack trace to stderr when a purge fails unexpectedly, matching the `bootstrap` command. Previously a failed purge printed only a generic message, giving operators no diagnostic information.
## [1.5.0]
diff --git a/runtime/admin/src/main/java/org/apache/polaris/admintool/PurgeCommand.java b/runtime/admin/src/main/java/org/apache/polaris/admintool/PurgeCommand.java
index 772d311d6b..426bea9d01 100644
--- a/runtime/admin/src/main/java/org/apache/polaris/admintool/PurgeCommand.java
+++ b/runtime/admin/src/main/java/org/apache/polaris/admintool/PurgeCommand.java
@@ -59,6 +59,7 @@ public class PurgeCommand extends BaseMetaStoreCommand {
spec.commandLine().getErr().printf("Purge encountered errors during operation.");
return EXIT_CODE_PURGE_ERROR;
} catch (Exception e) {
+ e.printStackTrace(spec.commandLine().getErr());
spec.commandLine().getErr().println("Purge encountered errors during operation.");
return EXIT_CODE_PURGE_ERROR;
}
diff --git a/runtime/admin/src/test/java/org/apache/polaris/admintool/PurgeCommandTest.java b/runtime/admin/src/test/java/org/apache/polaris/admintool/PurgeCommandTest.java
new file mode 100644
index 0000000000..27afe165d3
--- /dev/null
+++ b/runtime/admin/src/test/java/org/apache/polaris/admintool/PurgeCommandTest.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.polaris.admintool;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Map;
+import org.apache.polaris.core.config.RealmConfig;
+import org.apache.polaris.core.context.RealmContext;
+import org.apache.polaris.core.persistence.BasePersistence;
+import org.apache.polaris.core.persistence.MetaStoreManagerFactory;
+import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
+import org.apache.polaris.core.persistence.bootstrap.RootCredentialsSet;
+import org.apache.polaris.core.persistence.cache.EntityCache;
+import org.apache.polaris.core.persistence.dao.entity.BaseResult;
+import org.apache.polaris.core.persistence.dao.entity.PrincipalSecretsResult;
+import org.junit.jupiter.api.Test;
+import picocli.CommandLine;
+
+class PurgeCommandTest {
+
+ /**
+ * When {@code purgeRealms} fails (e.g. database connection failure, permission denied), the
+ * command must surface the underlying exception to stderr so operators can diagnose it, in
+ * addition to the generic error message and the purge error exit code.
+ */
+ @Test
+ void testPurgeFailurePrintsStackTrace() {
+ String failureMessage = "simulated database connection failure";
+ PurgeCommand command = new PurgeCommand();
+ command.metaStoreManagerFactory =
+ new ThrowingMetaStoreManagerFactory(new RuntimeException(failureMessage));
+
+ CommandLine commandLine = new CommandLine(command);
+ StringWriter err = new StringWriter();
+ commandLine.setErr(new PrintWriter(err));
+
+ int exitCode = commandLine.execute("-r", "realm1");
+
+ assertThat(exitCode).isEqualTo(BaseCommand.EXIT_CODE_PURGE_ERROR);
+ assertThat(err.toString())
+ .contains("java.lang.RuntimeException: " + failureMessage)
+ .contains("\tat ")
+ .contains("Purge encountered errors during operation.");
+ }
+
+ /** Minimal {@link MetaStoreManagerFactory} whose {@code purgeRealms} always throws. */
+ private static final class ThrowingMetaStoreManagerFactory implements MetaStoreManagerFactory {
+ private final RuntimeException failure;
+
+ private ThrowingMetaStoreManagerFactory(RuntimeException failure) {
+ this.failure = failure;
+ }
+
+ @Override
+ public Map<String, BaseResult> purgeRealms(Iterable<String> realms) {
+ throw failure;
+ }
+
+ @Override
+ public PolarisMetaStoreManager getOrCreateMetaStoreManager(RealmContext realmContext) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public BasePersistence getOrCreateSession(RealmContext realmContext) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public EntityCache getOrCreateEntityCache(RealmContext realmContext, RealmConfig realmConfig) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<String, PrincipalSecretsResult> bootstrapRealms(
+ Iterable<String> realms, RootCredentialsSet rootCredentialsSet) {
+ throw new UnsupportedOperationException();
+ }
+ }
+}