tursodatabase/turso · error · SQLException
Error reading ASCII stream
Error message
Error reading ASCII stream
What it means
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.
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.
Example fix
// before ps.setAsciiStream(1, requestBodyInputStream, len); // stream may be closed -> SQLException // after String ascii = new String(requestBodyInputStream.readAllBytes(), StandardCharsets.US_ASCII); ps.setString(1, ascii); // IO errors surface at readAllBytes with a clear stack trace
Defensive patterns
Strategy: try-catch
Validate before calling
// ensure the stream is open and unread before binding
if (in.available() >= 0 && !consumed) { // available() also forces a health probe
ps.setAsciiStream(i, in, length);
} Try / catch
try {
ps.setAsciiStream(i, in, length);
} catch (SQLException e) {
if (e.getCause() instanceof IOException ioe) {
// real cause is the stream: reopen/recreate it and retry
} else { throw e; }
} Prevention
- 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.
When it happens
Trigger: 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().
Common situations: 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.
Related errors
- Error reading binary stream
- Error reading Unicode stream
- setAsciiStream length must be non-negative
- setBinaryStream length must be non-negative
- setUnicodeStream length must be non-negative
AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20).
Data as JSON: /api/errors/49a4cf12cfc84133.
Report an issue: GitHub.
Appendix: 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 244cde92a7)