{"record":{"id":"49a4cf12cfc84133","repo":"tursodatabase/turso","slug":"error-reading-ascii-stream","errorCode":null,"errorMessage":"Error reading ASCII stream","messagePattern":"Error reading ASCII stream","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"bindings/java/src/main/java/tech/turso/jdbc4/JDBC4PreparedStatement.java","lineNumber":196,"sourceCode":"    }\n    if (length < 0) {\n      throw new SQLException(\"setAsciiStream 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 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 {","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/tursodatabase/turso/blob/244cde92a7df7f9b8b8b7a4075c35a12977e303e/bindings/java/src/main/java/tech/turso/jdbc4/JDBC4PreparedStatement.java#L178-L214","documentation":"While copying up to 'length' bytes from your InputStream in setAsciiStream(int, InputStream, int), an IOException from stream.read() is caught and rethrown as SQLException('Error reading ASCII stream') at JDBC4PreparedStatement.java:196, with the original IOException chained as the cause. The driver reads exactly once during this call; any stream defect (already closed, depleted, broken network source) surfaces here.","triggerScenarios":"Passing an already-closed stream; passing a stream whose underlying resource disappeared (closed socket, deleted temp file, expired blob URL); streams positioned past their end or single-use streams that were consumed by earlier logging/validation code; malformed custom InputStream implementations that throw from read().","commonSituations":"Reading request bodies/multipart uploads after the request stream was closed elsewhere; retry logic that reuses a consumed one-shot stream; streams over S3/HTTP connections that timed out during the copy; wrapping streams for logging which accidentally closes them.","solutions":["Inspect e.getCause() - it carries the real IOException explaining the failure.","Buffer the content fully before binding (read into byte[]/String, then setString) so IO errors happen under your control.","Ensure the stream is open and positioned at its start when passed, and not consumed by earlier code.","For network-backed streams, increase read timeouts or prefetch to a local temp file, then stream from disk.","On retry, recreate the stream from its source - streams are single-use."],"exampleFix":"// before\nps.setAsciiStream(1, requestBodyInputStream, len); // stream may be closed -> SQLException\n\n// after\nString ascii = new String(requestBodyInputStream.readAllBytes(), StandardCharsets.US_ASCII);\nps.setString(1, ascii); // IO errors surface at readAllBytes with a clear stack trace","handlingStrategy":"try-catch","validationCode":"// ensure the stream is open and unread before binding\nif (in.available() >= 0 && !consumed) { // available() also forces a health probe\n    ps.setAsciiStream(i, in, length);\n}","typeGuard":null,"tryCatchPattern":"try {\n    ps.setAsciiStream(i, in, length);\n} catch (SQLException e) {\n    if (e.getCause() instanceof IOException ioe) {\n        // real cause is the stream: reopen/recreate it and retry\n    } else { throw e; }\n}","preventionTips":["Buffer stream content (readAllBytes + setString) before binding.","Recreate streams from their source on every bind and retry.","Keep the underlying resource open until the bind completes.","Do not let logging/validation wrappers consume or close streams first."],"tags":["java","jdbc","turso","stream","io","parameter-binding"],"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"}