tursodatabase/turso · error · SQLException

setAsciiStream length must be non-negative

Error message

setAsciiStream length must be non-negative

What it means

JDBC4PreparedStatement.setAsciiStream(int, InputStream, int) validates its length argument before reading: a negative length is rejected with SQLException at JDBC4PreparedStatement.java:180. Some other drivers accept -1 as an 'unknown length, read to EOF' sentinel; this one does not. If you do not know the length up front, the two-argument overload setAsciiStream(int, InputStream) reads the whole stream.

Solutions

  1. If the length is unknown, use setAsciiStream(parameterIndex, stream) - it reads the stream to EOF.
  2. Compute the exact non-negative byte length before calling (e.g., file.length(), byte array length, buffered stream size).
  3. Validate and clamp: if (length < 0) length = (int) stream.available() or buffer fully and use setString.
  4. Fix the producer that supplies -1 so it reports the real size.

Example fix

// before
ps.setAsciiStream(1, in, -1); // -1 sentinel not accepted -> SQLException

// after
ps.setAsciiStream(1, in); // reads to EOF, no length needed
Defensive patterns

Strategy: validation

Validate before calling

if (length < 0) {
    ps.setAsciiStream(parameterIndex, stream); // unknown length: read to EOF
} else {
    ps.setAsciiStream(parameterIndex, stream, length);
}

Try / catch

try {
    ps.setAsciiStream(i, in, length);
} catch (SQLException e) {
    if (e.getMessage().contains("non-negative")) { ps.setAsciiStream(i, in); } else { throw e; }
}

Prevention

When it happens

Trigger: Passing -1 as a length sentinel copied from MySQL/PostgreSQL-oriented code; computing length via an underflowing subtraction or a signed conversion; passing a length obtained from a source that returns -1 for 'unknown' (e.g., some file/net layers); null stream is fine (binds NULL) - only negative length throws.

Common situations: Generic JDBC wrapper libraries that forward caller-supplied lengths verbatim; streaming uploads where the size is not known in advance and -1 is the codebase convention; ports of older code using the deprecated 3-arg stream API; unit tests with placeholder -1 values.

Related errors


AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20). Data as JSON: /api/errors/ba845743d5454c7b. Report an issue: GitHub.

Appendix: source

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

  public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException {
    requireNonNull(this.statement);
    if (x == null) {
      setParam(parameterIndex, null);
    } else {
      long time = x.getTime();
      setParam(parameterIndex, ByteBuffer.allocate(Long.BYTES).putLong(time).array());
    }
  }

  @Override
  public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {
    requireNonNull(this.statement);
    if (x == null) {
      setParam(parameterIndex, null);
      return;
    }
    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);
    }
  }

View on GitHub (pinned to 244cde92a7)