apache/seatunnel · error · IllegalArgumentException
oracle_insert_mode=APPEND_VALUES only supports generated INS
Error message
oracle_insert_mode=APPEND_VALUES only supports generated INSERT statements.
What it means
Thrown by JdbcOutputFormatBuilder.applyOracleAppendValuesHintIfNeeded when oracle_insert_mode=APPEND_VALUES is configured but the generated SQL does not start with INSERT. The APPEND_VALUES hint can only be injected into a plain INSERT statement, so any other statement shape is rejected as an IllegalArgumentException.
Source
Thrown at seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/JdbcOutputFormatBuilder.java:365
TableSchema databaseTableSchema,
JdbcRowConverter rowConverter) {
return new SimpleBatchStatementExecutor(
connection ->
FieldNamedPreparedStatement.prepareStatement(
connection, sql, tableSchema.getFieldNames()),
tableSchema,
databaseTableSchema,
rowConverter);
}
static String applyOracleAppendValuesHintIfNeeded(
JdbcSinkConfig jdbcSinkConfig, String insertSQL) {
if (!isOracleAppendValuesConfigured(jdbcSinkConfig)) {
return insertSQL;
}
final String insertPrefix = "INSERT";
if (!insertSQL.regionMatches(true, 0, insertPrefix, 0, insertPrefix.length())) {
throw new IllegalArgumentException(
"oracle_insert_mode=APPEND_VALUES only supports generated INSERT statements.");
}
String appendValuesSQL =
insertPrefix + " /*+ APPEND_VALUES */" + insertSQL.substring(insertPrefix.length());
log.info("Oracle APPEND_VALUES insert mode is enabled, generated SQL: {}", appendValuesSQL);
return appendValuesSQL;
}
private static void validateOracleInsertMode(
JdbcDialect dialect, JdbcSinkConfig jdbcSinkConfig, List<String> primaryKeys) {
if (!isOracleAppendValuesConfigured(jdbcSinkConfig)) {
return;
}
if (!DatabaseIdentifier.ORACLE.equals(dialect.dialectName())) {
throw new IllegalArgumentException(
"oracle_insert_mode=APPEND_VALUES only supports Oracle JDBC sink.");
}
if (primaryKeys != null && !primaryKeys.isEmpty()) {View on GitHub (pinned to cf67b549a7)
Solutions
- Remove the custom SQL override so the connector generates a standard INSERT statement
- Set oracle_insert_mode to the default (INSERT) if the statement is not a plain INSERT
- Ensure the dialect is Oracle and the sink is configured for insert-only writes
Example fix
// before generate_sink_sql = false sql = "MERGE INTO t USING ..." // after: let the connector generate INSERT sql = null generate_sink_sql = true
Defensive patterns
Strategy: validation
Validate before calling
// config sanity check before build
if (config.get("oracle_insert_mode") == "APPEND_VALUES" && config.get("sql") != null) {
throw new IllegalArgumentException("APPEND_VALUES requires generated INSERT SQL (no custom sql)");
} Try / catch
try { builder.build(); } catch (IllegalArgumentException e) {
if (e.getMessage().contains("APPEND_VALUES")) { /* fall back to default insert mode */ }
} Prevention
- Only enable APPEND_VALUES with auto-generated INSERT SQL
- Do not set oracle_insert_mode when overriding SQL
- Keep Oracle-only options out of generic configs
- Document the option's constraints for your team
When it happens
Trigger: Setting oracle_insert_mode=APPEND_VALUES while the builder produced a non-INSERT SQL statement (e.g. a custom/override SQL, or a statement generated for upsert semantics).
Common situations: Users copy a configuration using APPEND_VALUES onto a sink whose SQL was customized or auto-generated for MERGE/upsert mode; dialect changed from Oracle but the Oracle-specific option left in config.
Related errors
- oracle_insert_mode=APPEND_VALUES only supports Oracle JDBC s
- oracle_insert_mode=APPEND_VALUES only supports insert-only w
- No result returned after running query [${rowCountQuery}]
- No result returned after running query [${sqlQuery}]
- The source table[%s] is not found
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/a74442fd367d8206.
Report an issue: GitHub.