{"record":{"id":"16e7ce6d9cdd9ebd","repo":"tursodatabase/turso","slug":"error-reading-unicode-stream","errorCode":null,"errorMessage":"Error reading Unicode stream","messagePattern":"Error reading Unicode stream","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"bindings/java/src/main/java/tech/turso/jdbc4/JDBC4PreparedStatement.java","lineNumber":224,"sourceCode":"    }\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  }\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()) {","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/tursodatabase/turso/blob/244cde92a7df7f9b8b8b7a4075c35a12977e303e/bindings/java/src/main/java/tech/turso/jdbc4/JDBC4PreparedStatement.java#L206-L242","documentation":"setUnicodeStream(int, InputStream, int) reads up to 'length' bytes and decodes them as UTF-8; an IOException raised by stream.read() during that copy is wrapped as SQLException('Error reading Unicode stream') at JDBC4PreparedStatement.java:224 with the IOException as cause. The failure is in your stream, not the database - the binding never reaches the engine.","triggerScenarios":"Stream already closed or previously consumed (single-use streams read once by logging or validation); underlying source vanished (closed socket, deleted temp file, timed-out HTTP stream); custom InputStream subclasses that throw from read(); passing a Reader wrapped naively as a stream with mismatched length.","commonSituations":"Retry frameworks reusing an exhausted stream between attempts; web-upload code binding request streams that the container already closed; streams over remote storage (S3, HDFS) whose connection dropped mid-copy; double-binding code that reads the same stream for two parameters.","solutions":["Unwrap the cause via SQLException.getCause() to see the underlying IOException and fix that resource.","Read the whole stream into a byte[]/String before binding (readAllBytes + setString) so IO failures happen with clear stack traces under your control.","Recreate streams from their source on every bind/retry - never reuse a consumed stream.","Keep the stream's owner (file/socket/request) open for the duration of the setUnicodeStream call."],"exampleFix":"// before\nps.setUnicodeStream(1, networkStream, len); // IOException inside -> SQLException\n\n// after\nbyte[] bytes = networkStream.readAllBytes(); // explicit, retryable read\nps.setString(1, new String(bytes, StandardCharsets.UTF_8));","handlingStrategy":"try-catch","validationCode":"// buffer before binding so IO failures happen under your control\nbyte[] bytes = stream.readAllBytes(); // throws IOException here, clearly\nps.setString(parameterIndex, new String(bytes, StandardCharsets.UTF_8));","typeGuard":null,"tryCatchPattern":"try {\n    ps.setUnicodeStream(i, in, length);\n} catch (SQLException e) {\n    if (e.getCause() instanceof IOException ioe) {\n        // fix the stream source, recreate it, then retry the bind\n    } else { throw e; }\n}","preventionTips":["Never reuse a consumed stream; recreate from source.","Ensure the stream's owner (file/socket/request) stays open during the bind.","Prefetch remote content to local storage before streaming into JDBC.","Check e.getCause() first - the real failure is the chained IOException."],"tags":["java","jdbc","turso","stream","io","parameter-binding","deprecated-api"],"backgroundTag":"stream-read-ioexception","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"}