{"record":{"id":"f21c3394310bc09a","repo":"tursodatabase/turso","slug":"setunicodestream-length-must-be-non-negative","errorCode":null,"errorMessage":"setUnicodeStream length must be non-negative","messagePattern":"setUnicodeStream 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":208,"sourceCode":"      while (offset < length && (read = x.read(buffer, offset, length - offset)) > 0) {\n        offset += read;\n      }\n      String ascii = new String(buffer, 0, offset, StandardCharsets.US_ASCII);\n      setParam(parameterIndex, ascii);\n    } catch (IOException e) {\n      throw new SQLException(\"Error reading ASCII stream\", e);\n    }\n  }\n\n  @Override\n  public void setUnicodeStream(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(\"setUnicodeStream length must be non-negative\");\n    }\n    if (length == 0) {\n      setParam(parameterIndex, \"\");\n      return;\n    }\n    try {\n      byte[] buffer = new byte[length];\n      int offset = 0;\n      int read;\n      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  }","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/tursodatabase/turso/blob/244cde92a7df7f9b8b8b7a4075c35a12977e303e/bindings/java/src/main/java/tech/turso/jdbc4/JDBC4PreparedStatement.java#L190-L226","documentation":"JDBC4PreparedStatement.setUnicodeStream(int, InputStream, int) rejects a negative length with SQLException at JDBC4PreparedStatement.java:208 before touching the stream. This deprecated JDBC 1 method decodes the stream as UTF-8; the driver requires an explicit non-negative byte length and does not accept -1 as an 'unknown length' sentinel. Null streams are accepted and bind NULL.","triggerScenarios":"Passing -1 as a length sentinel (a convention tolerated by some other drivers); length computed from a char count, remaining bytes, or an underflowing calculation; forwarding caller-supplied lengths without validation in a generic data layer; test code using placeholder lengths.","commonSituations":"Legacy code still on the deprecated setUnicodeStream API being pointed at turso; wrappers/frameworks that mirror the old JDBC 1 trio (setAsciiStream/setUnicodeStream/setBinaryStream); migrations where the original database accepted loose length semantics.","solutions":["Migrate off the deprecated API: use setCharacterStream or setNString for unicode text, or setString directly.","If you must use it, compute and pass the exact non-negative byte length of the UTF-8 payload.","Buffer the stream into a String first, then call setString - removes length bookkeeping entirely.","Validate length >= 0 at the boundary of your wrapper and fail with your own clear message."],"exampleFix":"// before\nps.setUnicodeStream(1, utf8In, -1); // negative sentinel -> SQLException\n\n// after\nString text = new String(utf8In.readAllBytes(), StandardCharsets.UTF_8);\nps.setString(1, text);","handlingStrategy":"validation","validationCode":"if (length < 0) {\n    String text = new String(stream.readAllBytes(), StandardCharsets.UTF_8);\n    ps.setString(parameterIndex, text);\n} else {\n    ps.setUnicodeStream(parameterIndex, stream, length);\n}","typeGuard":null,"tryCatchPattern":"try {\n    ps.setUnicodeStream(i, in, length);\n} catch (SQLException e) {\n    if (e.getMessage().contains(\"non-negative\")) { /* recompute length or setString */ } else { throw e; }\n}","preventionTips":["Migrate off the deprecated setUnicodeStream to setString/setCharacterStream.","Pass exact non-negative byte lengths when the old API is required.","Reject -1 sentinels at your wrapper's boundary with a clear message.","Compute UTF-8 byte length, not char count, for this parameter."],"tags":["java","jdbc","turso","parameter-binding","stream","deprecated-api","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"}