apache/seatunnel · error · FactoryException
sourceOptionRule can not be null
Error message
sourceOptionRule can not be null
What it means
FactoryUtil.sourceFullOptionRule throws this FactoryException when the given TableSourceFactory's optionRule() returns null. SeaTunnel uses the option rule to expose full source configuration (e.g. to SeaTunnel Web), and a null rule is treated as a broken factory implementation.
Solutions
- Implement optionRule() in the TableSourceFactory to return a non-null OptionRule (OptionRule.builder()...build()).
- Upgrade the connector jar to a version that declares an option rule.
- If the connector genuinely has no options, return an empty OptionRule instead of null.
Example fix
// before
@Override
public OptionRule optionRule() { return null; }
// after
@Override
public OptionRule optionRule() {
return OptionRule.builder().required(DataSourceOptions.URL).optional(DataSourceOptions.USERNAME).build();
} Defensive patterns
Strategy: type-guard
Validate before calling
OptionRule rule = factory.optionRule();
if (rule == null) {
throw new IllegalStateException(factory.factoryIdentifier() + " must implement optionRule()");
} Type guard
boolean hasValidOptionRule(TableSourceFactory f) { return f.optionRule() != null; } Try / catch
try {
return FactoryUtil.sourceFullOptionRule(factory);
} catch (FactoryException e) {
throw new IllegalStateException("Connector must declare a non-null OptionRule", e);
} Prevention
- Every custom TableSourceFactory should implement optionRule() before release.
- Add a unit test asserting optionRule() != null for each connector factory.
- Upgrade third-party connectors that predate mandatory option rules.
When it happens
Trigger: Calling FactoryUtil.sourceFullOptionRule(factory) where factory is a custom/incomplete TableSourceFactory that overrides optionRule() to return null, or an old connector not yet migrated to declare an OptionRule.
Common situations: Developing a custom source connector and forgetting to implement optionRule(); using an outdated third-party connector jar against a newer API that requires a non-null option rule.
Related errors
- sinkOptionRule can not be null
- Could not find any factories that implement
- Could not find any factory for identifier
- Multiple factories for identifier
- SeaTunnelAPIErrorCode.CONFIG_VALIDATION_FAILED
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/c65c3a6a1abcd5de.
Report an issue: GitHub.
Appendix: source
Thrown at seatunnel-api/src/main/java/org/apache/seatunnel/api/table/factory/FactoryUtil.java:421
try {
final List<Factory> result = new LinkedList<>();
ServiceLoader.load(Factory.class, classLoader).iterator().forEachRemaining(result::add);
return result;
} catch (ServiceConfigurationError e) {
LOG.error("Could not load service provider for factories.", e);
throw new FactoryException("Could not load service provider for factories.", e);
}
}
/**
* This method is called by SeaTunnel Web to get the full option rule of a source.
*
* @return Option rule
*/
public static OptionRule sourceFullOptionRule(@NonNull TableSourceFactory factory) {
OptionRule sourceOptionRule = factory.optionRule();
if (sourceOptionRule == null) {
throw new FactoryException("sourceOptionRule can not be null");
}
Class<? extends SeaTunnelSource> sourceClass = factory.getSourceClass();
if (factory instanceof SupportParallelism
// TODO: Implement SupportParallelism in the TableSourceFactory instead of the
// SeaTunnelSource
|| SupportParallelism.class.isAssignableFrom(sourceClass)) {
OptionRule sourceCommonOptionRule =
OptionRule.builder().optional(EnvCommonOptions.PARALLELISM).build();
sourceOptionRule
.getOptionalOptions()
.addAll(sourceCommonOptionRule.getOptionalOptions());
}
return sourceOptionRule;
}
/**View on GitHub (pinned to cf67b549a7)