tursodatabase/turso · error · SQLException

Error reading ASCII stream

Error message

Error reading ASCII stream

What it means

setAsciiStream(int, InputStream, int) copies up to length bytes from the stream, decoding them as US-ASCII; any IOException raised by x.read during that copy is wrapped in this SQLException. The failure comes from the stream itself (closed handle, truncated file, dropped connection), not from SQL execution — the statement has not run yet when this is thrown.

Source

Thrown at bindings/java/src/main/java/tech/turso/jdbc4/JDBC4PreparedStatement.java:196

    }
    if (length < 0) {
      throw new SQLException("setAsciiStream length must be non-negative");
    }
    if (length == 0) {
      setParam(parameterIndex, "");
      return;
    }
    try {
      byte[] buffer = new byte[length];
      int offset = 0;
      int read;
      while (offset < length && (read = x.read(buffer, offset, length - offset)) > 0) {
        offset += read;
      }
      String ascii = new String(buffer, 0, offset, StandardCharsets.US_ASCII);
      setParam(parameterIndex, ascii);
    } catch (IOException e) {
      throw new SQLException("Error reading ASCII stream", e);
    }
  }

  @Override
  public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {
    requireNonNull(this.statement);
    if (x == null) {
      setParam(parameterIndex, null);
      return;
    }
    if (length < 0) {
      throw new SQLException("setUnicodeStream length must be non-negative");
    }
    if (length == 0) {
      setParam(parameterIndex, "");
      return;
    }
    try {

View on GitHub (pinned to bad083fafb)

Solutions

  1. Unwrap the cause: SQLException.getCause() holds the original IOException — fix whatever it reports (keep the source alive until the bind completes).
  2. Open the stream and bind it inside the same try-with-resources block so nothing closes it early.
  3. For remote or unstable sources, download to a byte[] or temp file first, then bind with setBytes or a ByteArrayInputStream.

Example fix

// before
InputStream in = Files.newInputStream(path);
// ...later: file deleted, read fails
ps.setAsciiStream(1, in, (int) size);

// after
try (InputStream in = Files.newInputStream(path)) {
    ps.setAsciiStream(1, in, (int) Files.size(path));
}
Defensive patterns

Strategy: try-catch

Validate before calling

// fail fast if the stream is already closed
try {
    in.available();
} catch (IOException closed) {
    throw new IllegalStateException("stream closed before binding", closed);
}

Try / catch

try {
    ps.setAsciiStream(1, in, len);
} catch (SQLException e) {
    if (e.getCause() instanceof IOException ioe) {
        // source-stream failure: reopen the source and retry once, or report context
        throw new DataAccessException("ASCII stream unreadable", ioe);
    }
    throw e;
}

Prevention

When it happens

Trigger: Passing an already-closed InputStream; the backing file is deleted or rotated between open and bind; a network or GZIP stream raises IOException mid-copy; another component consumed or invalidated the stream first.

Common situations: Log rotation deleting a file after FileInputStream creation; streaming from HTTP/S3 where the connection resets; streams closed by an outer try-with-resources before the bind call.

Related errors


AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16). Data as JSON: /api/errors/49a4cf12cfc84133. Report an issue: GitHub.