apache/iceberg · error · IllegalArgumentException
Invalid operator event type: <event.getClass().getCanonicalN
Error message
Invalid operator event type: <event.getClass().getCanonicalName()>
What it means
TriggerManagerOperator.handleOperatorEvent accepts only LockReleaseEvent (the lock-removed notification from the maintenance job). Any other OperatorEvent type is rejected with an IllegalArgumentException identifying the class. This indicates the operator received an event outside its expected protocol.
Source
Thrown at flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/maintenance/operator/TriggerManagerOperator.java:219
nextEvaluationTimeState.add(nextEvaluationTime);
}
accumulatedChangesState.update(accumulatedChanges);
lastTriggerTimesState.update(lastTriggerTimes);
LOG.info(
"Storing state: nextEvaluationTime {}, accumulatedChanges {}, lastTriggerTimes {}",
nextEvaluationTime,
accumulatedChanges,
lastTriggerTimes);
}
@Override
public void handleOperatorEvent(OperatorEvent event) {
if (event instanceof LockReleaseEvent) {
LOG.info("Received lock released event: {}", event);
handleLockRelease((LockReleaseEvent) event);
} else {
throw new IllegalArgumentException(
"Invalid operator event type: " + event.getClass().getCanonicalName());
}
}
@Override
public void processElement(StreamRecord<TableChange> streamRecord) throws Exception {
TableChange change = streamRecord.getValue();
accumulatedChanges.forEach(tableChange -> tableChange.merge(change));
if (nextEvaluationTime == null) {
checkAndFire(getProcessingTimeService());
} else {
LOG.info(
"Trigger manager rate limiter triggered current: {}, next: {}, accumulated changes: {},{}",
getProcessingTimeService().getCurrentProcessingTime(),
nextEvaluationTime,
accumulatedChanges,
maintenanceTaskNames);
rateLimiterTriggeredCounter.inc();View on GitHub (pinned to 86d9c8fc54)
Solutions
- Send only LockReleaseEvent to TriggerManagerOperator; LockRegisterEvent belongs on the coordinator side.
- Review the event-sending code path and the OperatorEventGateway used.
- If a new event type is needed, add an instanceof branch in handleOperatorEvent.
Example fix
// before operator.handleOperatorEvent(new LockRegisterEvent(factory, id)); // after operator.handleOperatorEvent(new LockReleaseEvent(taskId));
Defensive patterns
Strategy: type-guard
Validate before calling
if (!(event instanceof LockReleaseEvent)) { throw new IllegalStateException("TriggerManagerOperator only accepts LockReleaseEvent"); } Type guard
if (event instanceof LockReleaseEvent release) { /* release handling */ } Try / catch
try { operator.handleOperatorEvent(event); } catch (IllegalArgumentException e) { LOG.error("Unexpected operator event for trigger manager", e); } Prevention
- Only send LockReleaseEvent to the trigger manager operator
- Keep LockRegisterEvent on the coordinator side of the protocol
- Extend handleOperatorEvent explicitly when adding new event types
When it happens
Trigger: Calling handleOperatorEvent on a TriggerManagerOperator with anything other than a LockReleaseEvent (e.g. a LockRegisterEvent or custom event). Reached in tests testStateRestore/testLockCheckDelay and via Flink's operator event pathway.
Common situations: Custom code or tests sending wrong event types to the trigger manager operator; wiring changes where register events are mistakenly delivered to the operator instead of 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
- Invalid operator event type: <event.getClass().getCanonicalN
- Invalid operator event type: <event.getClass().getCanonicalN
- Unexpected delete file content: <deleteFile>
- Invalid operator event type: ${eventClassCanonicalName}
- Invalid operator event type:
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/b77f3a02762afc2f.
Report an issue: GitHub.