{"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/bad083fafbefdeae9a42ec19bdaaad8918dcf411/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; any IOException from the stream during the copy is wrapped in this SQLException. As with the ASCII variant, the statement never executes — the failure is in reading the caller's stream at bind time.","triggerScenarios":"Already-closed InputStream; file deleted or rotated after open; network-backed stream resetting during the bounded read; GZIP stream failing mid-decompression.","commonSituations":"File cleanup jobs racing the bind; streaming from remote object storage; a stream consumed earlier by logging or checksumming code.","solutions":["Inspect SQLException.getCause() for the real IOException and fix the source (keep it alive, add retries).","Open and bind the stream within one try-with-resources scope.","Migrate off the deprecated setUnicodeStream to setCharacterStream with an InputStreamReader(UTF-8) while you are fixing the lifecycle."],"exampleFix":"// before\nps.setUnicodeStream(1, in, len); // in was closed elsewhere\n\n// after\ntry (Reader r = new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8)) {\n    ps.setCharacterStream(1, r, len);\n}","handlingStrategy":"try-catch","validationCode":"// fail fast if the stream is already closed\ntry {\n    in.available();\n} catch (IOException closed) {\n    throw new IllegalStateException(\"stream closed before binding\", closed);\n}","typeGuard":null,"tryCatchPattern":"try {\n    ps.setUnicodeStream(1, in, len);\n} catch (SQLException e) {\n    if (e.getCause() instanceof IOException ioe) {\n        // stream failure — reopen source or fail with context; also plan migration to setCharacterStream\n    }\n    throw e;\n}","preventionTips":["Bind streams in the same scope where you open them.","Buffer untrusted sources to memory before binding.","Replace deprecated setUnicodeStream calls while touching this code."],"tags":["jdbc","io","stream","parameter-binding","deprecated"],"backgroundTag":"io-stream-read-failure","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}