{"record":{"id":"0e51036752ecdfbb","repo":"tursodatabase/turso","slug":"exception-while-binding-blob-value-at-position","errorCode":null,"errorMessage":"Exception while binding blob value at position \" + position","messagePattern":"Exception while binding blob value at position \" \\+ position","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"bindings/java/src/main/java/tech/turso/core/TursoStatement.java","lineNumber":210,"sourceCode":"    }\n    return result;\n  }\n\n  private native int bindText(long statementPointer, int position, String value)\n      throws SQLException;\n\n  /**\n   * Binds a blob value to the prepared statement at the specified position.\n   *\n   * @param position The index of the SQL parameter to be set.\n   * @param value The value to bind to the parameter.\n   * @return <a href=\"https://www.sqlite.org/c3ref/c_abort.html\">Result Codes</a>\n   * @throws SQLException If a database access error occurs.\n   */\n  public int bindBlob(int position, byte[] value) throws SQLException {\n    final int result = bindBlob(statementPointer, position, value);\n    if (result != 0) {\n      throw new SQLException(\"Exception while binding blob value at position \" + position);\n    }\n    return result;\n  }\n\n  private native int bindBlob(long statementPointer, int position, byte[] value)\n      throws SQLException;\n\n  public void bindObject(int parameterIndex, Object x) throws SQLException {\n    if (x == null) {\n      this.bindNull(parameterIndex);\n      return;\n    }\n    if (x instanceof Byte) {\n      this.bindInt(parameterIndex, (Byte) x);\n    } else if (x instanceof Short) {\n      this.bindInt(parameterIndex, (Short) x);\n    } else if (x instanceof Integer) {\n      this.bindInt(parameterIndex, (Integer) x);","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/bindings/java/src/main/java/tech/turso/core/TursoStatement.java#L192-L228","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nbyte[] avatar = Files.readAllBytes(path);\nps.bindBlob(0, avatar); // wrong: 0-based position\n\n// after\nbyte[] avatar = Files.readAllBytes(path);\nif (avatarIndex < 1 || avatarIndex > ps.parameterCount()) {\n    throw new IllegalArgumentException(\"bad bind position\");\n}\nps.bindBlob(avatarIndex, avatar);","handlingStrategy":"validation","validationCode":"if (stmt.isClosed()) throw new IllegalStateException(\"statement closed\");\nif (position < 1 || position > stmt.parameterCount()) {\n    throw new IllegalArgumentException(\"blob bind position out of range: \" + position);\n}\nstmt.bindBlob(position, bytes);","typeGuard":null,"tryCatchPattern":"try {\n    stmt.bindBlob(position, bytes);\n} catch (SQLException e) {\n    throw new IllegalStateException(\"bindBlob failed at \" + position, e);\n}","preventionTips":["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."],"tags":["java","jdbc","binding","blob","binary","parameter-position"],"backgroundTag":"jdbc-parameter-binding","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}