apache/druid · error · ISE

Cpu time must enabled

Error message

Cpu time must enabled

What it means

CPUTimeMetricQueryRunner's constructor requires JVM thread CPU-time measurement to be enabled, because it uses ThreadMXBean.getCurrentThreadCpuTime() to accumulate CPU-time metrics. If JvmUtils.isThreadCpuTimeEnabled() is false (ThreadMXBean null or CPU time unsupported), it throws an IllegalStateException rather than silently emitting no CPU metrics.

Solutions

  1. Run Druid on a supported HotSpot/OpenJDK JVM that supports thread CPU-time measurement, and don't disable CPU-time accounting via JVM flags.
  2. Set the query context flag so the CPU-time runner isn't wired in when metrics aren't needed (e.g. disable cpuTime metrics / use default query runner wrapping).
  3. If you build the runner yourself, guard with JvmUtils.isThreadCpuTimeEnabled() and fall back to the delegate runner without CPU metrics.
  4. Verify with a quick diagnostic that ManagementFactory.getThreadMXBean().isThreadCpuTimeEnabled() is true in your runtime before enabling the feature.

Example fix

// before
QueryRunner<T> runner = new CPUTimeMetricQueryRunner<>(delegate, chest, emitter, acc, true);
// after
if (JvmUtils.isThreadCpuTimeEnabled()) {
  runner = new CPUTimeMetricQueryRunner<>(delegate, chest, emitter, acc, true);
} else {
  runner = delegate;
}
Defensive patterns

Strategy: validation

Validate before calling

if (!JvmUtils.isThreadCpuTimeEnabled()) {
  // skip CPU-time wrapping
  runner = delegate;
} else {
  runner = new CPUTimeMetricQueryRunner<>(delegate, chest, emitter, acc, report);
}

Type guard

boolean cpuTimeAvailable() {
  java.lang.management.ThreadMXBean bean = java.lang.management.ManagementFactory.getThreadMXBean();
  return bean instanceof com.sun.management.ThreadMXBean && bean.isThreadCpuTimeSupported() && bean.isThreadCpuTimeEnabled();
}

Try / catch

try {
  return new CPUTimeMetricQueryRunner<>(delegate, chest, emitter, acc, report);
} catch (IllegalStateException e) {
  if (e.getMessage().contains("Cpu time must enabled")) {
    return delegate; // proceed without CPU metrics
  }
  throw e;
}

Prevention

When it happens

Trigger: Building a CPUTimeMetricQueryRunner (typically via QueryToolChest.wrap / mergeResults wiring) on a JVM where thread CPU time is unavailable: -XX:-UseThreadPriorities-style disabling, JREs without com.sun.management.ThreadMXBean support, or JVMs where isThreadCpuTimeEnabled() returns false at startup.

Common situations: Running Druid on minimal/JVM variants lacking HotSpot ThreadMXBean CPU-time support; unusual runtime environments (some containers or alternate JVM vendors) where getCurrentThreadCpuTime is unsupported; misconfigured JVM flags disabling CPU-time measurement.

Related errors


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

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/query/CPUTimeMetricQueryRunner.java:50

public class CPUTimeMetricQueryRunner<T> implements QueryRunner<T>
{
  private final QueryRunner<T> delegate;
  private final QueryToolChest<T, ? extends Query<T>> queryToolChest;
  private final ServiceEmitter emitter;
  private final AtomicLong cpuTimeAccumulator;
  private final boolean report;

  private CPUTimeMetricQueryRunner(
      QueryRunner<T> delegate,
      QueryToolChest<T, ? extends Query<T>> queryToolChest,
      ServiceEmitter emitter,
      AtomicLong cpuTimeAccumulator,
      boolean report
  )
  {
    if (!JvmUtils.isThreadCpuTimeEnabled()) {
      throw new ISE("Cpu time must enabled");
    }
    this.delegate = delegate;
    this.queryToolChest = queryToolChest;
    this.emitter = emitter;
    this.cpuTimeAccumulator = cpuTimeAccumulator == null ? new AtomicLong(0L) : cpuTimeAccumulator;
    this.report = report;
  }

  @Override
  public Sequence<T> run(final QueryPlus<T> queryPlus, final ResponseContext responseContext)
  {
    final long startRun = JvmUtils.getCurrentThreadCpuTime();
    final QueryPlus<T> queryWithMetrics = queryPlus.withQueryMetrics(queryToolChest);
    final Sequence<T> baseSequence = delegate.run(queryWithMetrics, responseContext);

    cpuTimeAccumulator.addAndGet(JvmUtils.getCurrentThreadCpuTime() - startRun);

    return Sequences.wrap(

View on GitHub (pinned to 9b90983fd2)