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
- Run Druid on a supported HotSpot/OpenJDK JVM that supports thread CPU-time measurement, and don't disable CPU-time accounting via JVM flags.
- 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).
- If you build the runner yourself, guard with JvmUtils.isThreadCpuTimeEnabled() and fall back to the delegate runner without CPU metrics.
- 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
- Deploy on standard HotSpot/OpenJDK JVMs that support thread CPU time.
- Avoid JVM flags or restricted environments that disable ThreadMXBean CPU-time accounting.
- Check JvmUtils.isThreadCpuTimeEnabled() once at service startup and configure metric wiring accordingly.
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
- Can only handle [ ], got [ ]
- Cannot determine maxDirectMemory from
- CLEANER_NOT_SUPPORTED_EXCEPTION
- Cleaning is not support on this platform, because internal…
- Counter increment amount must be non-negative, but got value
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)