{"record":{"id":"ec4c7e9750944ff4","repo":"tursodatabase/turso","slug":"setbinarystream-length-must-be-non-negative","errorCode":null,"errorMessage":"setBinaryStream length must be non-negative","messagePattern":"setBinaryStream length must be non-negative","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"bindings/java/src/main/java/tech/turso/jdbc4/JDBC4PreparedStatement.java","lineNumber":236,"sourceCode":"      while (offset < length && (read = x.read(buffer, offset, length - offset)) > 0) {\n        offset += read;\n      }\n      String text = new String(buffer, 0, offset, StandardCharsets.UTF_8);\n      setParam(parameterIndex, text);\n    } catch (IOException e) {\n      throw new SQLException(\"Error reading Unicode stream\", e);\n    }\n  }\n\n  @Override\n  public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {\n    requireNonNull(this.statement);\n    if (x == null) {\n      setParam(parameterIndex, null);\n      return;\n    }\n    if (length < 0) {\n      throw new SQLException(\"setBinaryStream length must be non-negative\");\n    }\n    if (length == 0) {\n      setParam(parameterIndex, new byte[0]);\n      return;\n    }\n    try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {\n      byte[] buffer = new byte[8192];\n      int bytesRead;\n      int totalRead = 0;\n      while (totalRead < length\n          && (bytesRead = x.read(buffer, 0, Math.min(buffer.length, length - totalRead))) > 0) {\n        baos.write(buffer, 0, bytesRead);\n        totalRead += bytesRead;\n      }\n      byte[] data = baos.toByteArray();\n      setParam(parameterIndex, data);\n    } catch (IOException e) {\n      throw new SQLException(\"Error reading binary stream\", e);","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/tursodatabase/turso/blob/244cde92a7df7f9b8b8b7a4075c35a12977e303e/bindings/java/src/main/java/tech/turso/jdbc4/JDBC4PreparedStatement.java#L218-L254","documentation":"JDBC4PreparedStatement.setBinaryStream(int, InputStream, int) validates that length is >= 0 and throws SQLException at JDBC4PreparedStatement.java:236 otherwise. The driver copies exactly 'length' bytes from the stream into a BLOB parameter; a -1 'unknown length' sentinel, accepted by some other drivers, is rejected here. Use the two-argument setBinaryStream(int, InputStream) overload when the size is unknown.","triggerScenarios":"Passing -1 (or any negative int) as length, commonly the 'read to end' convention from other drivers; lengths derived from File.length() cast incorrectly, subtraction underflow, or -1 returned by a size-lookup helper; wrapper APIs forwarding user-supplied lengths unchecked; null stream is allowed (binds NULL), only negative length throws.","commonSituations":"File-upload code where the size probe failed and -1 leaked into the bind call; generic JDBC layers ported from MySQL Connector/J or the PostgreSQL driver; big-binary insert code written against tutorials using the 3-arg API; tests with placeholder lengths.","solutions":["Switch to setBinaryStream(parameterIndex, stream) - it reads to EOF and needs no length.","Or buffer the payload (Files.readAllBytes / readAllBytes) and use setBytes(index, bytes).","Compute the length from a reliable source (file length, array length) and fail fast yourself if it cannot be determined.","Audit generic wrapper code for forwarded lengths and validate length >= 0 at the boundary."],"exampleFix":"// before\nps.setBinaryStream(1, fileIn, -1); // -1 sentinel -> SQLException\n\n// after\nps.setBinaryStream(1, fileIn); // reads to EOF\n// or: ps.setBytes(1, Files.readAllBytes(path));","handlingStrategy":"validation","validationCode":"if (length < 0) {\n    ps.setBinaryStream(parameterIndex, stream); // unknown length: read to EOF\n} else {\n    ps.setBinaryStream(parameterIndex, stream, length);\n}","typeGuard":null,"tryCatchPattern":"try {\n    ps.setBinaryStream(i, in, length);\n} catch (SQLException e) {\n    if (e.getMessage().contains(\"non-negative\")) { ps.setBinaryStream(i, in); } else { throw e; }\n}","preventionTips":["Use the two-argument overload or setBytes when size is unknown.","Treat any -1 from a size probe as 'compute it properly', never forward it.","Validate lengths at wrapper boundaries before reaching the driver.","Prefer byte[] buffering for file-backed payloads."],"tags":["java","jdbc","turso","parameter-binding","stream","blob","input-validation"],"backgroundTag":"negative-stream-length","analyzedSha":"244cde92a7df7f9b8b8b7a4075c35a12977e303e","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}