apache/seatunnel · error · IllegalArgumentException
Unsupported required option type
Error message
Unsupported required option type: ${requiredOptionClassName} What it means
toRequiredOptionMetadata converts a RequiredOption instance into REST response metadata. It resolves a RuleType via resolveRuleType(requiredOption); if the resolver returns null the RequiredOption implementation class is not one of the known types (e.g. MultiChoiceOption, ConditionalRequiredOptions), so an IllegalArgumentException with the class name is thrown. This is an internal invariant against unhandled RequiredOption implementations.
Solutions
- Upgrade the engine server so OptionRulesService is in sync with the seatunnel-api version producing the OptionRule
- Add a mapping for the new RequiredOption type in resolveRuleType and handle it in toRequiredOptionMetadata
- Inspect the class name in the message and file an issue/patch in OptionRulesService.java around line 231
- Check for mixed jar versions of seatunnel-api on the server classpath
Example fix
// before (in resolveRuleType)
if (requiredOption instanceof RequiredOption.RequiredOptions) return ...;
// after — add the missing type
if (requiredOption instanceof MyNewRequiredOption) {
return OptionRuleResponse.RuleType.MY_NEW_TYPE;
} Defensive patterns
Strategy: try-catch
Validate before calling
// ensure engine-server and seatunnel-api versions match assert OptionRulesService.class.getPackage() != null; // and check dependency tree
Type guard
boolean supported(RequiredOption o) { return o instanceof RequiredOption.RequiredOptions || o instanceof RequiredOption.ConditionalRequiredOptions || o instanceof MultiChoiceOption; } Try / catch
try { renderRule(rule); } catch (IllegalArgumentException e) { log.error("Unsupported RequiredOption: {}", e.getMessage()); return fallbackMetadata(); } Prevention
- Keep engine-server and seatunnel-api on the same release
- Add a resolveRuleType branch whenever a new RequiredOption type is introduced
- Add a unit test covering all RequiredOption implementations
When it happens
Trigger: Rendering option rules for a plugin whose OptionRule contains a RequiredOption subclass that resolveRuleType does not map — typically after a new RequiredOption type is added to seatunnel-api without updating OptionRulesService.
Common situations: SeaTunnel core upgraded with a new option-rule type while the engine-server REST module (or its dependency version) is stale; a custom plugin returns a bespoke RequiredOption implementation; mixed jar versions in the Zeta cluster.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Invalid option rules request, type
- array inject error, unsupported data type: " + type
- Avro format doesn't support non-string as key type of map…
- Cannot modify column
- COMMON-17
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/6386e1571c7d9a54.
Report an issue: GitHub.
Appendix: source
Thrown at seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/rest/service/OptionRulesService.java:231
}
private String normalizePluginName(String pluginName) {
if (StringUtils.isBlank(pluginName)) {
throw new IllegalArgumentException(
String.format("Parameter '%s' cannot be empty.", PARAM_PLUGIN));
}
return pluginName.trim().toLowerCase(Locale.ROOT);
}
private OptionRuleResponse.RequiredOptionMetadata toRequiredOptionMetadata(
RequiredOption requiredOption) {
List<OptionRuleResponse.OptionMetadata> options =
requiredOption.getOptions().stream()
.map(this::toOptionMetadata)
.collect(Collectors.toList());
OptionRuleResponse.RuleType ruleType = resolveRuleType(requiredOption);
if (ruleType == null) {
throw new IllegalArgumentException(
String.format(
"Unsupported required option type: %s",
requiredOption.getClass().getName()));
}
if (requiredOption instanceof RequiredOption.ConditionalRequiredOptions) {
Expression expression =
((RequiredOption.ConditionalRequiredOptions) requiredOption).getExpression();
return new OptionRuleResponse.RequiredOptionMetadata(
ruleType, options, expression.toString(), toExpressionNode(expression));
}
return new OptionRuleResponse.RequiredOptionMetadata(ruleType, options, null, null);
}
private OptionRuleResponse.ConditionRuleMetadata toConditionRuleMetadata(
ConditionRule conditionRule) {
Expression expression = conditionRule.getExpression();
return new OptionRuleResponse.ConditionRuleMetadata(
expression.toString(),View on GitHub (pinned to cf67b549a7)