{"record":{"id":"7340cec17cd3bc5e","repo":"apache/seatunnel","slug":"the-sql-config-must-contain-insert-into-selec","errorCode":null,"errorMessage":"The SQL config must contain `INSERT INTO ... SELECT ...` syntax","messagePattern":"The SQL config must contain `INSERT INTO \\.\\.\\. SELECT \\.\\.\\.` syntax","errorType":"exception","errorClass":"ParserException","httpStatus":null,"severity":"error","filePath":"seatunnel-config/seatunnel-config-sql/src/main/java/org/apache/seatunnel/config/sql/SqlConfigBuilder.java","lineNumber":158,"sourceCode":"            seaTunnelConfig.setSinkConfigs(\n                    seaTunnelConfig.getSinkConfigs().stream()\n                            .filter(\n                                    sinkConfig -> {\n                                        boolean containSourceTable = false;\n                                        for (Option option : sinkConfig.getOptions()) {\n                                            if (option.getKey().equals(OPTION_PLUGIN_INPUT_KEY)) {\n                                                containSourceTable = true;\n                                                break;\n                                            }\n                                        }\n                                        return containSourceTable;\n                                    })\n                            .collect(Collectors.toList()));\n            if (seaTunnelConfig.getSourceConfigs().isEmpty()) {\n                throw new ParserException(\"The SQL config must contain at least one source table\");\n            }\n            if (seaTunnelConfig.getSinkConfigs().isEmpty()) {\n                throw new ParserException(\n                        \"The SQL config must contain `INSERT INTO ... SELECT ...` syntax\");\n            }\n\n            // render to hocon config\n            String configContent = ConfigTemplate.generate(seaTunnelConfig);\n            log.debug(\"Generated config: \\n{}\", configContent);\n            return ConfigFactory.parseString(configContent);\n        } catch (ParserException e) {\n            throw e;\n        } catch (Exception e) {\n            throw new ParserException(e);\n        }\n    }\n\n    private static List<String> parseAnnoConfigAndSqlLine(\n            List<String> lines, SeaTunnelConfig seaTunnelConfig) {\n        List<String> sqlLines = new ArrayList<>();\n        List<String> annotationConfigs = new ArrayList<>();","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-config/seatunnel-config-sql/src/main/java/org/apache/seatunnel/config/sql/SqlConfigBuilder.java#L140-L176","documentation":"SqlConfigBuilder requires at least one sink config, produced only by INSERT statements; if sinkConfigs is empty after parsing it throws ParserException telling the user the config must contain `INSERT INTO ... SELECT ...` syntax. A job that only declares tables but never inserts is invalid.","triggerScenarios":"The .sql file contains only CREATE TABLE statements (sources and/or intermediate tables) with no INSERT INTO ... SELECT statement.","commonSituations":"Authoring only schema definitions expecting seatunnel to auto-wire, INSERT statements that failed the instanceof Insert check due to syntax quirks, or the sink filtered out because its plugin_input didn't match.","solutions":["Add an INSERT INTO <sink_table> SELECT ... FROM <source_table> statement.","Verify the INSERT parses correctly as a JSqlParser Insert (no exotic syntax).","Ensure the sink CREATE TABLE exists and its name matches the INSERT target.","Check plugin_input/plugin_output identifiers line up so the sink isn't filtered out."],"exampleFix":"// before\nCREATE TABLE src WITH ('connector'='fake', 'type'='source') (id INT);\n-- no insert: job has no sink\n// after\nCREATE TABLE src WITH ('connector'='fake', 'type'='source') (id INT);\nCREATE TABLE sink WITH ('connector'='console', 'type'='sink') (id INT);\nINSERT INTO sink SELECT id FROM src;","handlingStrategy":"validation","validationCode":"boolean hasInsert = Files.readAllLines(sqlFile).stream().anyMatch(l -> l.trim().toUpperCase().startsWith(\"INSERT INTO\"));","typeGuard":null,"tryCatchPattern":"try { Config c = SqlConfigBuilder.of(sqlFile); } catch (ParserException e) { if (e.getMessage().contains(\"INSERT INTO\")) { /* add an INSERT statement */ } }","preventionTips":["Every job needs INSERT INTO sink SELECT ... FROM source","Keep sink table name identical to the INSERT target","Check plugin_input/plugin_output wiring so sinks aren't filtered","Lint for INSERT presence before submission"],"tags":["sql-config","config-validation","missing-sink","java"],"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-14T05:17:10.506Z"}