apache/seatunnel · error · IllegalArgumentException

Unsupported metric class: ${metricClass}

Error message

Unsupported metric class: ${metricClass}

What it means

ConnectorMetricsCalcContext.createMetric instantiates a metric from a MetricsContext by class: only Counter and Meter are supported. If a connector declares a metric of another class (e.g. Gauge, Histogram, DistributionSummary), IllegalArgumentException 'Unsupported metric class' is thrown when the metric is created via newMetric.

Source

Thrown at seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/metrics/ConnectorMetricsCalcContext.java:334

        } else {
            String metricName =
                    PluginType.SINK.equals(type)
                            ? sinkMetric + "#" + tableName
                            : sourceMetric + "#" + tableName;
            T newMetric = createMetric(metricsContext, metricName, cls);
            processor.process(newMetric);
            metricMap.put(tableName, newMetric);
        }
    }

    private <T> T createMetric(
            MetricsContext metricsContext, String metricName, Class<T> metricClass) {
        if (metricClass == Counter.class) {
            return metricClass.cast(metricsContext.counter(metricName));
        } else if (metricClass == Meter.class) {
            return metricClass.cast(metricsContext.meter(metricName));
        }
        throw new IllegalArgumentException("Unsupported metric class: " + metricClass.getName());
    }

    @FunctionalInterface
    interface MetricProcessor<T> {
        void process(T t);
    }

    private static final class PendingMetrics {
        private long count;
        private long bytes;
        private final Map<String, TablePendingMetrics> tableMetrics = new ConcurrentHashMap<>();

        void add(String tableName, long rowBytes) {
            count++;
            bytes += rowBytes;
            if (StringUtils.isNotBlank(tableName)) {
                tableMetrics
                        .computeIfAbsent(tableName, key -> new TablePendingMetrics())

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Change the connector metric to a supported type: Counter for counts, Meter for rates.
  2. If you need gauge-like values, model them as a Counter updated by the connector.
  3. Check the SeaTunnel version - newer metric types may require upgrading the engine.
  4. Fix any generic metric factory code that passes unexpected Class<T> values into createMetric.

Example fix

// before
@Metric
Gauge<Double> queueSize();
// after
@Metric
Counter enqueuedCount();
Defensive patterns

Strategy: validation

Validate before calling

Class<?> c = metric.getMetric().getClass();
if (c != Counter.class && c != Meter.class) {
    throw new IllegalArgumentException("connector metric must be Counter or Meter: " + c.getName());
}

Type guard

static boolean isSupportedMetric(Object m) {
    return m instanceof Counter || m instanceof Meter;
}

Try / catch

try {
    MetricsContext.register(connectorMetrics);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Unsupported metric class")) {
        log.warn("skipping unsupported metric: {}", e.getMessage());
    } else throw e;
}

Prevention

When it happens

Trigger: A Source/Sink/Transform declares a metric via @Metric with a getMetric() returning a type other than Counter or Meter, and the metrics system calls newMetric -> createMetric for that connector metric during job metric initialization.

Common situations: Custom connector exposing a Gauge or Histogram metric; connector code updated to a new metric type not yet supported by the engine's metrics bridge; generic helper returning Object cast to an unsupported Class<T>.

Related errors


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/04f2616d2296718a. Report an issue: GitHub.