tursodatabase/turso · error · SQLException
Exception while binding NULL value at position " + position
Error message
Exception while binding NULL value at position " + position
What it means
TursoStatement.bindNull(position) checks the native bind's result code and throws unless it is 0 (SQLITE_OK). Non-zero typically means the position is outside 1..parameterCount() for the prepared SQL, or the statement is in a state that no longer accepts binds (already stepped without reset, or closed).
Source
Thrown at bindings/java/src/main/java/tech/turso/core/TursoStatement.java:120
if (columnNames != null) {
this.resultSet.setColumnNames(columnNames);
}
}
@Nullable
private native String[] columns(long statementPointer) throws SQLException;
/**
* Binds a NULL value to the prepared statement at the specified position.
*
* @param position The index of the SQL parameter to be set to NULL.
* @return <a href="https://www.sqlite.org/c3ref/c_abort.html">Result Codes</a>
* @throws SQLException If a database access error occurs.
*/
public int bindNull(int position) throws SQLException {
final int result = bindNull(statementPointer, position);
if (result != 0) {
throw new SQLException("Exception while binding NULL value at position " + position);
}
return result;
}
private native int bindNull(long statementPointer, int position) throws SQLException;
/**
* Binds an integer value to the prepared statement at the specified position. This function calls
* bindLong because turso treats all integers as long (as well as SQLite).
*
* <p>According to SQLite documentation, the value is a signed integer, stored in 0, 1, 2, 3, 4,
* 6, or 8 bytes depending on the magnitude of the value.
*
* @param position The index of the SQL parameter to be set.
* @param value The integer value to bind to the parameter.
* @return A result code indicating the success or failure of the operation.
* @throws SQLException If a database access error occurs.
*/View on GitHub (pinned to bad083fafb)
Solutions
- Use 1-based positions and verify against stmt.parameterCount() before binding
- Call stmt.reset() before re-binding a statement that already stepped or executed
- Keep the SQL and the bind sequence in sync — count the ? placeholders when editing queries
- Loop parameters with for (int i = 1; i <= stmt.parameterCount(); i++)
Example fix
// before
for (int i = 0; i < n; i++) stmt.bindNull(i); // position 0 -> non-zero result code
// after
for (int i = 1; i <= stmt.parameterCount(); i++) {
stmt.bindNull(i);
} Defensive patterns
Strategy: validation
Validate before calling
int count = stmt.parameterCount();
if (position >= 1 && position <= count) {
stmt.bindNull(position);
} else {
throw new IllegalArgumentException(
"bind position " + position + " outside 1.." + count);
} Type guard
static boolean isValidBindPosition(TursoStatement stmt, int position) throws SQLException {
return position >= 1 && position <= stmt.parameterCount();
} Prevention
- Always bind with 1-based positions — placeholders are numbered from 1
- Call stmt.reset() before re-binding a statement for the next execution
- Count the ? placeholders whenever you edit a parameterized query, and prefer parameterCount() over hardcoded counts
When it happens
Trigger: Binding with a 0-based position (bindNull(0)); a position beyond the number of ? parameters in the SQL (e.g. bindNull(3) on a query with two placeholders); re-binding a statement for the next batch without calling reset(); binding on a closed statement. Note bindObject(...) routes null values here too.
Common situations: for (int i = 0; i < n; i++) stmt.bindNull(i) loops; SQL edited to remove a placeholder while bind code kept the old positions; PreparedStatement.setObject(i, null) on paths that funnel into bindObject; batch re-execution missing reset().
Related errors
- SQLite only supports TYPE_FORWARD_ONLY cursors
- SQLite only supports CONCUR_READ_ONLY cursors
- SQLite only supports closing cursors at commit
- Cannot commit in autocommit mode.
- Cannot rollback in autocommit mode.
AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16).
Data as JSON: /api/errors/35abaa36e4776245.
Report an issue: GitHub.