{"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/bad083fafbefdeae9a42ec19bdaaad8918dcf411/bindings/java/src/main/java/tech/turso/jdbc4/JDBC4PreparedStatement.java#L190-L226","documentation":"Thrown by setUnicodeStream(int, InputStream, int) when length is negative. setUnicodeStream is the deprecated JDBC 1 stream API; this driver still implements it (copying length bytes and decoding as UTF-8) but enforces a non-negative length exactly like setAsciiStream. A null stream binds SQL NULL and a zero length binds an empty string; only negative lengths throw.","triggerScenarios":"ps.setUnicodeStream(i, in, -1) or a negative computed length; legacy code paths that still call the deprecated method and use -1 as an 'unknown length' sentinel.","commonSituations":"Old JDBC 1-era codebases kept alive; lengths read from external config that default to -1; maintainers surprised that the deprecated method still validates its arguments.","solutions":["Pass a non-negative byte count.","Replace setUnicodeStream with setCharacterStream(i, reader, length) — the supported replacement with identical semantics for UTF-8 text.","For unknown length use the no-length setCharacterStream(i, reader) overload rather than a sentinel."],"exampleFix":"// before\nps.setUnicodeStream(1, in, -1);\n\n// after\nps.setCharacterStream(1, new InputStreamReader(in, StandardCharsets.UTF_8));","handlingStrategy":"validation","validationCode":"if (length < 0) {\n    throw new IllegalArgumentException(\"length must be >= 0, got \" + length);\n}\nps.setCharacterStream(1, new InputStreamReader(in, StandardCharsets.UTF_8), length);","typeGuard":null,"tryCatchPattern":"catch (SQLException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"non-negative\")) {\n        // fix the length argument; consider migrating to setCharacterStream\n    }\n    throw e;\n}","preventionTips":["Prefer setCharacterStream over the deprecated setUnicodeStream everywhere.","Treat -1 as an invalid length, never as 'read to EOF'.","Keep one shared stream-binding helper with length validation."],"tags":["jdbc","parameter-binding","input-validation","deprecated"],"backgroundTag":"jdbc-invalid-parameter-value","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}