apache/iceberg · error · IllegalArgumentException

Invalid operator event type: <event.getClass().getCanonicalN

Error message

Invalid operator event type: <event.getClass().getCanonicalName()>

What it means

The Iceberg Flink maintenance LockRemoverCoordinator only accepts OperatorEvents that are instances of LockReleaseEvent. Any other OperatorEvent sent from a subtask to this coordinator is rejected with an IllegalArgumentException naming the unexpected event's canonical class name. This is an internal protocol guard: it means an event reached the wrong coordinator.

Source

Thrown at flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/maintenance/operator/LockRemoverCoordinator.java:49

  LockRemoverCoordinator(String operatorName, Context context) {
    super(operatorName, context);
    LOG.info("Created LockRemoverCoordinator: {}", operatorName);
  }

  @Override
  public void handleEventFromOperator(int subtask, int attemptNumber, OperatorEvent event) {
    runInCoordinatorThread(
        () -> {
          LOG.debug(
              "Handling event from subtask {} (#{}) of {}: {}",
              subtask,
              attemptNumber,
              operatorName(),
              event);
          if (event instanceof LockReleaseEvent) {
            handleReleaseLock((LockReleaseEvent) event);
          } else {
            throw new IllegalArgumentException(
                "Invalid operator event type: " + event.getClass().getCanonicalName());
          }
        },
        String.format(
            Locale.ROOT,
            "handling operator event %s from subtask %d (#%d)",
            event.getClass(),
            subtask,
            attemptNumber));
  }
}

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Check which coordinator you are sending the event to; LockRegisterEvent must go to TriggerManagerCoordinator, LockReleaseEvent to LockRemoverCoordinator.
  2. Verify the OperatorEventGateway used by your operator is obtained from the intended coordinator's context.
  3. If you wrote a custom OperatorEvent, subclass LockReleaseEvent or register handling for it in the coordinator before sending.

Example fix

// before
eventGateway.sendOperatorEvent(new LockRegisterEvent(lockFactory, lockId)); // sent to LockRemoverCoordinator
// after
// send register events to the TriggerManager coordinator, release events to the lock remover
triggerGateway.sendOperatorEvent(new LockRegisterEvent(lockFactory, lockId));
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(event instanceof LockReleaseEvent)) { throw new IllegalStateException("Wrong coordinator for event " + event.getClass()); }

Type guard

if (event instanceof LockReleaseEvent release) { /* handle */ }

Try / catch

try { coordinator.handleEventFromOperator(subtask, attempt, event); } catch (IllegalArgumentException e) { LOG.error("Event routed to wrong coordinator", e); }

Prevention

When it happens

Trigger: Calling OperatorCoordinator.handleEventFromOperator with an OperatorEvent that is not a LockReleaseEvent (e.g. a LockRegisterEvent sent to the wrong coordinator, or a custom event).

Common situations: Wiring the TriggerManager's lock-register events into the maintenance job's LockRemover coordinator, mixing operator event types between the trigger and maintenance portions of the table maintenance flow, or custom code firing arbitrary OperatorEvents at the coordinator.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/c4159b7464b29273. Report an issue: GitHub.