{"record":{"id":"c65c3a6a1abcd5de","repo":"apache/seatunnel","slug":"sourceoptionrule-can-not-be-null","errorCode":null,"errorMessage":"sourceOptionRule can not be null","messagePattern":"sourceOptionRule can not be null","errorType":"validation","errorClass":"FactoryException","httpStatus":null,"severity":"error","filePath":"seatunnel-api/src/main/java/org/apache/seatunnel/api/table/factory/FactoryUtil.java","lineNumber":421,"sourceCode":"        try {\n            final List<Factory> result = new LinkedList<>();\n            ServiceLoader.load(Factory.class, classLoader).iterator().forEachRemaining(result::add);\n            return result;\n        } catch (ServiceConfigurationError e) {\n            LOG.error(\"Could not load service provider for factories.\", e);\n            throw new FactoryException(\"Could not load service provider for factories.\", e);\n        }\n    }\n\n    /**\n     * This method is called by SeaTunnel Web to get the full option rule of a source.\n     *\n     * @return Option rule\n     */\n    public static OptionRule sourceFullOptionRule(@NonNull TableSourceFactory factory) {\n        OptionRule sourceOptionRule = factory.optionRule();\n        if (sourceOptionRule == null) {\n            throw new FactoryException(\"sourceOptionRule can not be null\");\n        }\n\n        Class<? extends SeaTunnelSource> sourceClass = factory.getSourceClass();\n        if (factory instanceof SupportParallelism\n                // TODO: Implement SupportParallelism in the TableSourceFactory instead of the\n                // SeaTunnelSource\n                || SupportParallelism.class.isAssignableFrom(sourceClass)) {\n            OptionRule sourceCommonOptionRule =\n                    OptionRule.builder().optional(EnvCommonOptions.PARALLELISM).build();\n            sourceOptionRule\n                    .getOptionalOptions()\n                    .addAll(sourceCommonOptionRule.getOptionalOptions());\n        }\n\n        return sourceOptionRule;\n    }\n\n    /**","sourceCodeStart":403,"sourceCodeEnd":439,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/factory/FactoryUtil.java#L403-L439","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n@Override\npublic OptionRule optionRule() { return null; }\n// after\n@Override\npublic OptionRule optionRule() {\n    return OptionRule.builder().required(DataSourceOptions.URL).optional(DataSourceOptions.USERNAME).build();\n}","handlingStrategy":"type-guard","validationCode":"OptionRule rule = factory.optionRule();\nif (rule == null) {\n    throw new IllegalStateException(factory.factoryIdentifier() + \" must implement optionRule()\");\n}","typeGuard":"boolean hasValidOptionRule(TableSourceFactory f) { return f.optionRule() != null; }","tryCatchPattern":"try {\n    return FactoryUtil.sourceFullOptionRule(factory);\n} catch (FactoryException e) {\n    throw new IllegalStateException(\"Connector must declare a non-null OptionRule\", e);\n}","preventionTips":["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."],"tags":["option-rule","factory","api-contract"],"backgroundTag":"method-not-implemented","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}