apache/beam · error · RuntimeException

Error while setting data to preparedStatement

Error message

Error while setting data to preparedStatement

What it means

During JdbcIO write, each schema field is bound to the PreparedStatement via a registered field setter (preparedStatementFieldSetterList). If ResultSet/row field binding throws SQLException while calling set(...) for any index, it is wrapped in this RuntimeException. It indicates the row data could not be written into the SQL statement parameters.

Solutions

  1. Read the wrapped SQLException cause to identify which parameter/column failed and why.
  2. Ensure the Beam Row schema matches the table column types and nullability.
  3. Truncate or convert values that exceed column size/precision before writing.
  4. Provide a custom statement and PreparedStatementSetter via withStatement()/withPreparedStatementSetter() to control binding yourself.

Example fix

// before
row -> Row.withSchema(schema).addValues(longString) // exceeds VARCHAR(10)
// after
row -> Row.withSchema(schema).addValues(longString.substring(0, 10)) // or widen the column
Defensive patterns

Strategy: validation

Validate before calling

// validate row data against table DDL before writing
for (Schema.Field f : row.getSchema().getFields()) {
  Object v = row.getValue(f.getName());
  if (v == null && !f.getType().getNullable()) {
    throw new IllegalArgumentException("NOT NULL column has no value: " + f.getName());
  }
  if (v instanceof String && ((String) v).length() > maxLenForColumn(f.getName())) {
    throw new IllegalArgumentException("Value too long for column: " + f.getName());
  }
}

Try / catch

try {
  rows.apply(JdbcIO.<Row>writeWithSchema());
} catch (RuntimeException e) {
  if ("Error while setting data to preparedStatement".equals(e.getMessage())) {
    SQLException sql = (SQLException) e.getCause(); // find failing parameter via cause chain
  }
  throw e;
}

Prevention

When it happens

Trigger: Writing a Beam Row via JdbcIO.write() where a field value is incompatible with the target column (type mismatch, value out of range for the column type, inserting NULL into a NOT NULL column), or a setter registered for the field throws during preparedStatement.setXxx().

Common situations: Schema evolved (e.g. string longer than VARCHAR column), logical types not matching driver expectations, inserting nulls into non-nullable columns, or timezone/precision issues with DATETIME/TIMESTAMP fields.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/bbd056bd3324bdea. Report an issue: GitHub.

Appendix: source

Thrown at sdks/java/io/jdbc/src/main/java/org/apache/beam/sdk/io/jdbc/JdbcIO.java:2618

                (index) -> {
                  Schema.FieldType fieldType = fields.get(index).getField().getType();
                  preparedStatementFieldSetterList.add(
                      JdbcUtil.getPreparedStatementSetCaller(fieldType));
                });
      }

      @Override
      public void setParameters(T element, PreparedStatement preparedStatement) throws Exception {
        Row row = (element instanceof Row) ? (Row) element : toRowFn.apply(element);
        IntStream.range(0, fields.size())
            .forEach(
                (index) -> {
                  try {
                    preparedStatementFieldSetterList
                        .get(index)
                        .set(row, preparedStatement, index, fields.get(index));
                  } catch (SQLException e) {
                    throw new RuntimeException("Error while setting data to preparedStatement", e);
                  }
                });
      }
    }

    private boolean hasStatementAndSetter() {
      return getStatement() != null && getPreparedStatementSetter() != null;
    }
  }

  private static class Reparallelize<T> extends PTransform<PCollection<T>, PCollection<T>> {
    @Override
    public PCollection<T> expand(PCollection<T> input) {
      // See https://issues.apache.org/jira/browse/BEAM-2803
      // We use a combined approach to "break fusion" here:
      // (see https://cloud.google.com/dataflow/service/dataflow-service-desc#preventing-fusion)
      // 1) force the data to be materialized by passing it as a side input to an identity fn,
      // then 2) reshuffle it with a random key. Initial materialization provides some parallelism

View on GitHub (pinned to 12126d8942)