apache/druid · error · java.lang.RuntimeException

Unable to run cleaning action

Error message

Unable to run cleaning action

What it means

The Cleanable returned by Cleaners wraps a MethodHandle invocation of the JDK cleanable's clean(). If running that cleaning action throws, the lambda rethrows it as RuntimeException 'Unable to run cleaning action'. This means the underlying clean() call failed, typically because the cleanable was already cleaned or internal APIs misbehaved.

Solutions

  1. Clean each resource exactly once; treat explicit clean as terminal and drop the reference afterwards.
  2. Wrap clean() calls in try/catch of RuntimeException and ignore 'already cleaned'-style failures if idempotency is desired.
  3. Verify JVM compatibility; on standard JDKs double-clean is the usual culprit.

Example fix

// before
cleanable.clean();
cleanable.clean(); // second call throws
// after
cleanable.clean(); // once only; GC will handle the rest
Defensive patterns

Strategy: try-catch

Try / catch

try {
  cleanable.clean();
} catch (RuntimeException e) {
  // likely already cleaned; ignore or log
}

Prevention

When it happens

Trigger: Explicitly calling clean() (via the Cleanable) twice, or after the JVM already auto-cleaned the object; or the reflective clean invocation failing on an incompatible runtime.

Common situations: Double-cleaning resources, race between GC-triggered automatic cleaning and explicit clean, exotic JDKs where clean() behaves unexpectedly.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/b9ebb834e04cd6a4. Report an issue: GitHub.

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/java/util/common/Cleaners.java:136

    public Cleanable register(Object object, Runnable runnable)
    {
      try {
        Object cleanable = (Object) register.invoke(object, runnable);
        return createCleanable(clean, cleanable);
      }
      catch (Throwable t) {
        throw new RuntimeException("Unable to register cleaning action", t);
      }
    }

    private static Cleanable createCleanable(MethodHandle clean, Object cleanable)
    {
      return () -> {
        try {
          clean.invoke(cleanable);
        }
        catch (Throwable t) {
          throw new RuntimeException("Unable to run cleaning action", t);
        }
      };
    }
  }
}

View on GitHub (pinned to 9b90983fd2)