{"record":{"id":"0edd5c395c430be8","repo":"tursodatabase/turso","slug":"error-reading-inputstream","errorCode":null,"errorMessage":"Error reading InputStream","messagePattern":"Error reading InputStream","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"bindings/java/src/main/java/tech/turso/jdbc4/JDBC4PreparedStatement.java","lineNumber":605,"sourceCode":"   * @return a byte array containing the data\n   * @throws SQLException if an I/O error occurs while reading\n   */\n  private byte[] readBytes(InputStream x) throws SQLException {\n    try {\n      int firstByte = x.read();\n      if (firstByte == -1) {\n        return new byte[0];\n      }\n      ByteArrayOutputStream baos = new ByteArrayOutputStream();\n      baos.write(firstByte);\n      byte[] buffer = new byte[8192];\n      int bytesRead;\n      while ((bytesRead = x.read(buffer)) > 0) {\n        baos.write(buffer, 0, bytesRead);\n      }\n      return baos.toByteArray();\n    } catch (IOException e) {\n      throw new SQLException(\"Error reading InputStream\", e);\n    }\n  }\n\n  @Override\n  public void setCharacterStream(int parameterIndex, @Nullable Reader reader) throws SQLException {\n    requireNonNull(this.statement);\n    if (reader == null) {\n      setParam(parameterIndex, null);\n      return;\n    }\n    try {\n      StringBuilder sb = new StringBuilder();\n      char[] buffer = new char[8192];\n      int read;\n      while ((read = reader.read(buffer)) != -1) {\n        sb.append(buffer, 0, read);\n      }\n      setParam(parameterIndex, sb.toString());","sourceCodeStart":587,"sourceCodeEnd":623,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/bindings/java/src/main/java/tech/turso/jdbc4/JDBC4PreparedStatement.java#L587-L623","documentation":"The no-length setAsciiStream(int, InputStream) and setBinaryStream(int, InputStream) overloads drain the whole stream eagerly via the readBytes helper: one probe byte, then 8 KiB chunks until EOF. Any IOException during that copy is wrapped in this SQLException. An empty stream is legal (probe byte == -1 binds an empty value); this error means the stream actually failed mid-read, at bind time — not later at execute.","triggerScenarios":"Already-closed or invalidated stream; HTTP/S3-backed stream resetting mid-copy; GZIP stream hitting corruption while being drained; file deleted after open.","commonSituations":"Object-storage streams without client-side retry; streams closed by an outer scope before the set* call; two components sharing one stream instance.","solutions":["Unwrap SQLException.getCause() for the original IOException and fix the producer (timeouts, retries, keep-alive).","Stabilize remote streams first: read them fully into a byte[] with your own retry, then bind with setBytes; or download to a temp file.","Open and bind the stream inside one try-with-resources block — the copy happens during the set* call itself."],"exampleFix":"// before\nInputStream in = objectStore.open(key); // may reset mid-read\nps.setBinaryStream(1, in);\n\n// after\nbyte[] data = retryingReadAll(objectStore, key); // buffered + retried\nps.setBytes(1, data);","handlingStrategy":"try-catch","validationCode":"// fail fast if the stream is already closed\ntry {\n    in.available();\n} catch (IOException e) {\n    throw new IllegalStateException(\"stream closed before binding\", e);\n}","typeGuard":null,"tryCatchPattern":"try {\n    ps.setBinaryStream(1, in);\n} catch (SQLException e) {\n    if (e.getCause() instanceof IOException ioe) {\n        // stream failure: reopen/retry the source, or fail with context\n    }\n    throw e;\n}","preventionTips":["The driver copies the stream during the set* call itself — closed-before-bind is the common failure mode.","Buffer remote/untrusted streams (readAllBytes + retry) and bind with setBytes.","Never share one stream between consumers; the driver drains it fully."],"tags":["jdbc","io","stream","parameter-binding"],"backgroundTag":"io-stream-read-failure","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}