{"record":{"id":"8519c96900e45600","repo":"apache/seatunnel","slug":"plugin-name-is-required-but-missing","errorCode":null,"errorMessage":"Plugin name is required but missing","messagePattern":"Plugin name is required but missing","errorType":"validation","errorClass":"ConfigCheckException","httpStatus":null,"severity":"error","filePath":"seatunnel-core/seatunnel-starter/src/main/java/org/apache/seatunnel/core/starter/seatunnel/command/SeaTunnelConfValidateCommand.java","lineNumber":317,"sourceCode":"     * <p>The caller is responsible for setting {@code pluginClassLoader} as the thread context\n     * classloader before calling this method so that {@link FactoryUtil#discoverFactory} resolves\n     * the correct factories.\n     *\n     * @param pluginConfigs raw plugin {@link Config} blocks to validate\n     * @param factoryClass the factory interface to discover (source / transform / sink)\n     * @param pluginClassLoader the classloader with the connector JARs on its search path\n     */\n    private void validatePluginConfigs(\n            List<? extends Config> pluginConfigs,\n            Class<? extends Factory> factoryClass,\n            ClassLoader pluginClassLoader)\n            throws ConfigCheckException {\n        for (Config pluginConfig : pluginConfigs) {\n            ReadonlyConfig readonlyConfig = ReadonlyConfig.fromConfig(pluginConfig);\n            String pluginName = readonlyConfig.getOptional(PLUGIN_NAME).orElse(\"\");\n\n            if (StringUtils.isBlank(pluginName)) {\n                throw new ConfigCheckException(\"Plugin name is required but missing\");\n            }\n\n            Factory factory =\n                    FactoryUtil.discoverFactory(pluginClassLoader, factoryClass, pluginName);\n\n            ConfigValidator.of(readonlyConfig).validate(factory.optionRule());\n            validateOptionTypes(readonlyConfig, factory.optionRule());\n            ConfigValidator.validateUnknownKeys(readonlyConfig, factory.optionRule(), pluginName);\n\n            if (\"Sql\".equalsIgnoreCase(pluginName)\n                    && TableTransformFactory.class.isAssignableFrom(factoryClass)) {\n                validateSqlTransformSyntax(pluginConfig, pluginClassLoader);\n            }\n        }\n    }\n\n    private void validateSqlTransformSyntax(Config pluginConfig, ClassLoader pluginClassLoader)\n            throws ConfigCheckException {","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-core/seatunnel-starter/src/main/java/org/apache/seatunnel/core/starter/seatunnel/command/SeaTunnelConfValidateCommand.java#L299-L335","documentation":"Each plugin block in a SeaTunnel config must declare a `plugin_name` identifying which Source/Transform/Sink factory to instantiate. validatePluginConfigs throws this ConfigCheckException when a plugin config's plugin_name is absent or blank, before factory discovery is attempted. It fails fast so the user knows which structural requirement of the config is unmet.","triggerScenarios":"A source/transform/sink block in the job config has no `plugin_name` option, or it is set to an empty/whitespace string; validatePluginConfigs iterates the parsed plugin configs and finds one blank.","commonSituations":"Hand-edited HOCON configs where the plugin_name line was deleted, programmatically generated configs omitting the field, or renaming the key to something like `name` instead of `plugin_name`.","solutions":["Add `plugin_name = \"<PluginName>\"` to every source/transform/sink block in the config","Verify the key is spelled exactly `plugin_name` (not `name` or `plugin`)","Check for stray empty plugin blocks `{}` left in the config file","Validate locally with `seatunnel.sh --validate ...` before submitting"],"exampleFix":"// before\nsource {\n  {\n    url = \"jdbc:mysql://localhost:3306/test\"\n  }\n}\n// after\nsource {\n  Jdbc {\n    url = \"jdbc:mysql://localhost:3306/test\"\n    driver = \"com.mysql.cj.jdbc.Driver\"\n    plugin_name = \"Jdbc\"\n  }\n}","handlingStrategy":"validation","validationCode":"for (Config pluginConfig : pluginConfigs) {\n    String name = ReadonlyConfig.fromConfig(pluginConfig).getOptional(PLUGIN_NAME).orElse(null);\n    if (name == null || name.trim().isEmpty()) {\n        throw new IllegalArgumentException(\"Each plugin block requires a non-empty plugin_name\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    validatePluginConfigs(...);\n} catch (ConfigCheckException e) {\n    if (e.getMessage().contains(\"Plugin name is required\")) {\n        log.error(\"A source/transform/sink block is missing plugin_name\");\n    }\n}","preventionTips":["Always include plugin_name in every plugin block","Use official example configs as templates","Lint HOCON configs for required keys before submit","Never hand-rename config option keys"],"tags":["config-validation","plugin-name","seatunnel-core"],"backgroundTag":"missing-required-config-field","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"}