apache/seatunnel · error · ParserException
Insert sql must have select statement
Error message
Insert sql must have select statement
What it means
Validation in SqlConfigBuilder.parseInsertSql: an INSERT statement in the SQL config must be INSERT INTO ... SELECT; an insert whose body does not contain a Select (e.g. INSERT ... VALUES) cannot be translated into a SeaTunnel pipeline and is rejected with ParserException.
Source
Thrown at seatunnel-config/seatunnel-config-sql/src/main/java/org/apache/seatunnel/config/sql/SqlConfigBuilder.java:371
} else {
throw new ParserException(String.format("Unsupported syntax: %s", createTable));
}
}
private static void parseInsertSql(
Insert insertSql,
Map<String, BaseConfig> sqlTables,
SeaTunnelConfig seaTunnelConfig,
AtomicInteger tempTableIndex) {
if (insertSql.getColumns() != null && !insertSql.getColumns().isEmpty()) {
throw new ParserException("Insert sql must not have columns");
}
TransformConfig transformConfig = new TransformConfig();
Select select = insertSql.getSelect();
if (select == null
|| select.getSelectBody() == null
|| !(select.getSelectBody() instanceof PlainSelect)) {
throw new ParserException("Insert sql must have select statement");
}
String targetTableName = insertSql.getTable().getName();
if (select.getSelectBody() instanceof PlainSelect) {
PlainSelect plainSelect = (PlainSelect) select.getSelectBody();
String pluginInputIdentifier;
String pluginOutputIdentifier;
if (plainSelect.getFromItem() == null) {
List<SelectItem<?>> selectItems = plainSelect.getSelectItems();
if (selectItems.size() != 1) {
throw new ParserException(
"Source table must be specified in SQL: " + insertSql);
}
SelectItem<?> selectItem = selectItems.get(0);
Column column = (Column) selectItem.getExpression();
pluginInputIdentifier = column.getColumnName();
pluginOutputIdentifier = pluginInputIdentifier;
} else {View on GitHub (pinned to cf67b549a7)
Solutions
- Replace VALUES (...) with an equivalent 'SELECT ... ' from a source table or a fake/dataset source
- Rewrite UNION/CTE bodies into a single plain SELECT
- Ensure the INSERT statement is complete and ends with a SELECT clause
Example fix
// before INSERT INTO sink_t VALUES (1, 'a') // after INSERT INTO sink_t SELECT 1, 'a' FROM src
Defensive patterns
Strategy: validation
Validate before calling
// ensure each INSERT has a plain SELECT body
for (String stmt : insertStatements(sql)) {
if (!stmt.matches("(?si)INSERT\\s+INTO\\s+\\w+\\s+SELECT\\s+.*")) {
throw new IllegalArgumentException("INSERT must be followed by a plain SELECT: " + stmt);
}
} Try / catch
try {
SeaTunnelConfig c = SqlConfigBuilder.of(sql);
} catch (ParserException e) {
if (e.getMessage().equals("Insert sql must have select statement")) {
// replace VALUES/compound select with plain SELECT
}
} Prevention
- Do not use INSERT ... VALUES in this dialect; generate rows via a source table
- Keep INSERT queries as single plain SELECTs (no UNION/CTE)
- Validate SQL with JSqlParser before submission
When it happens
Trigger: INSERT INTO sink_t VALUES (...); INSERT ... with a UNION/CTE select body; truncated SQL missing the SELECT entirely.
Common situations: Porting row-value INSERT syntax from standard SQL; using multi-table or compound select statements the simple parser rejects.
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
- Insert sql must not have columns
- Unsupported syntax: <insertSql>
- Unsupported syntax: %s
- Source table must be specified in SQL: <insertSql>
- The sink table[%s] is not found
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/ba3ec834f9ab0521.
Report an issue: GitHub.