{"record":{"id":"80271aced849e782","repo":"tursodatabase/turso","slug":"error-reading-binary-stream","errorCode":null,"errorMessage":"Error reading binary stream","messagePattern":"Error reading binary stream","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"bindings/java/src/main/java/tech/turso/jdbc4/JDBC4PreparedStatement.java","lineNumber":254,"sourceCode":"      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()) {\n      byte[] buffer = new byte[8192];\n      int bytesRead;\n      int totalRead = 0;\n      while (totalRead < length\n          && (bytesRead = x.read(buffer, 0, Math.min(buffer.length, length - totalRead))) > 0) {\n        baos.write(buffer, 0, bytesRead);\n        totalRead += bytesRead;\n      }\n      byte[] data = baos.toByteArray();\n      setParam(parameterIndex, data);\n    } catch (IOException e) {\n      throw new SQLException(\"Error reading binary stream\", e);\n    }\n  }\n\n  @Override\n  public void clearParameters() {\n    this.currentBatchParams = new Object[paramCount];\n  }\n\n  @Override\n  public void clearBatch() throws SQLException {\n    this.batchQueryParams.clear();\n    this.currentBatchParams = new Object[paramCount];\n  }\n\n  @Override\n  public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {\n    // TODO\n  }","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/bindings/java/src/main/java/tech/turso/jdbc4/JDBC4PreparedStatement.java#L236-L272","documentation":"setBinaryStream(int, InputStream, int) copies the stream through an 8 KiB buffer into a ByteArrayOutputStream; an IOException from x.read — the only call that can throw here, since ByteArrayOutputStream.write is unchecked — is wrapped in this SQLException. Note that a short stream does NOT throw: if EOF arrives before length bytes, the driver silently binds only the bytes actually read, so verify sizes separately if truncation matters.","triggerScenarios":"Already-closed stream; file deleted mid-read; network stream reset while the copy loop is running; truncated upload being bound with its advertised length.","commonSituations":"Streams from HTTP/S3 dropping mid-transfer; files removed by retention jobs between open and bind; silent truncation going unnoticed because short reads do not error.","solutions":["Inspect getCause() for the original IOException and fix the source stream lifecycle.","Keep the source alive until the bind returns; open it in the same scope (try-with-resources).","Buffer remote streams first (readAllBytes with your own retry) and bind with setBytes; also verify the byte count matches expectations to catch silent truncation."],"exampleFix":"// before\nps.setBinaryStream(1, in, len); // in already closed elsewhere\n\n// after\ntry (InputStream in = Files.newInputStream(path)) {\n    ps.setBinaryStream(1, in, (int) Files.size(path));\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.setBinaryStream(1, in, len);\n} catch (SQLException e) {\n    if (e.getCause() instanceof IOException ioe) {\n        // stream failure — reopen/retry the source, or buffer first and use setBytes\n    }\n    throw e;\n}","preventionTips":["Keep the source alive until the bind returns; open in try-with-resources.","Remember short reads bind silently — verify byte counts if truncation matters.","Buffer remote streams with your own retry before binding."],"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"}