tursodatabase/turso · error · SQLException

setUnicodeStream length must be non-negative

Error message

setUnicodeStream length must be non-negative

What it means

Thrown by setUnicodeStream(int, InputStream, int) when length is negative. setUnicodeStream is the deprecated JDBC 1 stream API; this driver still implements it (copying length bytes and decoding as UTF-8) but enforces a non-negative length exactly like setAsciiStream. A null stream binds SQL NULL and a zero length binds an empty string; only negative lengths throw.

Source

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

      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 {
      byte[] buffer = new byte[length];
      int offset = 0;
      int read;
      while (offset < length && (read = x.read(buffer, offset, length - offset)) > 0) {
        offset += read;
      }
      String text = new String(buffer, 0, offset, StandardCharsets.UTF_8);
      setParam(parameterIndex, text);
    } catch (IOException e) {
      throw new SQLException("Error reading Unicode stream", e);
    }
  }

View on GitHub (pinned to bad083fafb)

Solutions

  1. Pass a non-negative byte count.
  2. Replace setUnicodeStream with setCharacterStream(i, reader, length) — the supported replacement with identical semantics for UTF-8 text.
  3. For unknown length use the no-length setCharacterStream(i, reader) overload rather than a sentinel.

Example fix

// before
ps.setUnicodeStream(1, in, -1);

// after
ps.setCharacterStream(1, new InputStreamReader(in, StandardCharsets.UTF_8));
Defensive patterns

Strategy: validation

Validate before calling

if (length < 0) {
    throw new IllegalArgumentException("length must be >= 0, got " + length);
}
ps.setCharacterStream(1, new InputStreamReader(in, StandardCharsets.UTF_8), length);

Try / catch

catch (SQLException e) {
    if (e.getMessage() != null && e.getMessage().contains("non-negative")) {
        // fix the length argument; consider migrating to setCharacterStream
    }
    throw e;
}

Prevention

When it happens

Trigger: ps.setUnicodeStream(i, in, -1) or a negative computed length; legacy code paths that still call the deprecated method and use -1 as an 'unknown length' sentinel.

Common situations: Old JDBC 1-era codebases kept alive; lengths read from external config that default to -1; maintainers surprised that the deprecated method still validates its arguments.

Related errors


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