tursodatabase/turso · error · SQLException
Exception while binding blob value at position " + position
Error message
Exception while binding blob value at position " + position
What it means
Thrown when the JNI-native bindBlob call returns a non-zero result. The native code first resolves the statement pointer (failing with SQLITE_ERROR if the statement is closed or the handle is stale), converts the byte[] via JNI (conversion failure also returns SQLITE_ERROR), then calls bind_at which rejects out-of-range 1-based positions. Blob size is not validated at this layer.
Source
Thrown at bindings/java/src/main/java/tech/turso/core/TursoStatement.java:210
}
return result;
}
private native int bindText(long statementPointer, int position, String value)
throws SQLException;
/**
* Binds a blob value to the prepared statement at the specified position.
*
* @param position The index of the SQL parameter to be set.
* @param value The value to bind to the parameter.
* @return <a href="https://www.sqlite.org/c3ref/c_abort.html">Result Codes</a>
* @throws SQLException If a database access error occurs.
*/
public int bindBlob(int position, byte[] value) throws SQLException {
final int result = bindBlob(statementPointer, position, value);
if (result != 0) {
throw new SQLException("Exception while binding blob value at position " + position);
}
return result;
}
private native int bindBlob(long statementPointer, int position, byte[] value)
throws SQLException;
public void bindObject(int parameterIndex, Object x) throws SQLException {
if (x == null) {
this.bindNull(parameterIndex);
return;
}
if (x instanceof Byte) {
this.bindInt(parameterIndex, (Byte) x);
} else if (x instanceof Short) {
this.bindInt(parameterIndex, (Short) x);
} else if (x instanceof Integer) {
this.bindInt(parameterIndex, (Integer) x);View on GitHub (pinned to bad083fafb)
Solutions
- Use 1-based parameter positions and check them against parameterCount().
- Guard with isClosed() before binding blobs on long-lived statements.
- Rebuild prepared statements after any error path that may have closed them rather than blindly reusing.
- Add an assertion layer in test builds that binds match the SQL placeholder count.
Example fix
// before
byte[] avatar = Files.readAllBytes(path);
ps.bindBlob(0, avatar); // wrong: 0-based position
// after
byte[] avatar = Files.readAllBytes(path);
if (avatarIndex < 1 || avatarIndex > ps.parameterCount()) {
throw new IllegalArgumentException("bad bind position");
}
ps.bindBlob(avatarIndex, avatar); Defensive patterns
Strategy: validation
Validate before calling
if (stmt.isClosed()) throw new IllegalStateException("statement closed");
if (position < 1 || position > stmt.parameterCount()) {
throw new IllegalArgumentException("blob bind position out of range: " + position);
}
stmt.bindBlob(position, bytes); Try / catch
try {
stmt.bindBlob(position, bytes);
} catch (SQLException e) {
throw new IllegalStateException("bindBlob failed at " + position, e);
} Prevention
- Validate position against parameterCount() before binding blobs.
- Do not bind binary payloads on pooled/recycled statements.
- In upload handlers, bind bytes in the same try block that executes the statement.
- Guard long-lived statement fields with isClosed() before use.
When it happens
Trigger: stmt.bindBlob(position, bytes) with position 0 or beyond parameterCount(); binding a blob after statement close(); passing a byte[] on a statement whose connection is closed.
Common situations: File/image upload code binding binary payloads; 0-based array-index habits carried over into parameter positions; statements kept as long-lived fields and reused after an error path already closed them.
Related errors
- Exception while binding long value at position " + position
- Exception while binding double value at position " + positio
- Exception while binding text value at position " + position
- createBlob not supported
- database connection closed
AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16).
Data as JSON: /api/errors/0e51036752ecdfbb.
Report an issue: GitHub.