apache/shardingsphere · error · IllegalArgumentException

SQL federation pagination parameter value `%s` must be an in

Error message

SQL federation pagination parameter value `%s` must be an integer.

What it means

StandardSQLFederationProcessor validates LIMIT/OFFSET pagination parameter values for federated execution. A Number parameter whose decimal form is not exactly an integer (e.g. 1.5, or a double with fraction) fails BigDecimal.toBigIntegerExact() and throws IllegalArgumentException stating the value must be an integer. A separate sibling check enforces the 0..Integer.MAX_VALUE range.

Source

Thrown at kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/engine/processor/impl/StandardSQLFederationProcessor.java:191

        paginationContext.getOffsetParameterIndex().ifPresent(result::add);
        paginationContext.getRowCountParameterIndex().ifPresent(result::add);
    }
    
    private Object convertPaginationParameter(final Object value) {
        if (!(value instanceof Number)) {
            return value;
        }
        BigInteger integerValue = getIntegerValue((Number) value);
        ShardingSpherePreconditions.checkState(integerValue.compareTo(MIN_PAGINATION_PARAMETER) >= 0 && integerValue.compareTo(MAX_PAGINATION_PARAMETER) <= 0,
                () -> new IllegalArgumentException(String.format("SQL federation pagination parameter value `%s` is out of integer range.", value)));
        return integerValue.intValue();
    }
    
    private BigInteger getIntegerValue(final Number value) {
        try {
            return new BigDecimal(value.toString()).toBigIntegerExact();
        } catch (final NumberFormatException | ArithmeticException ex) {
            throw new IllegalArgumentException(String.format("SQL federation pagination parameter value `%s` must be an integer.", value), ex);
        }
    }
    
    @Override
    public Convention getConvention() {
        return EnumerableConvention.INSTANCE;
    }
}

View on GitHub (pinned to e952770a21)

Solutions

  1. Bind integral types for LIMIT/OFFSET parameters (setInt/setLong), or round/truncate to whole numbers before binding.
  2. Validate computed pagination values in application code before executing the query.
  3. If a decimal like 10.0 arrives as Double, normalize it: BigDecimal.valueOf(d).setScale(0, RoundingMode.DOWN) when the semantic is a whole count.

Example fix

// before
ps.setObject(1, pageSizePercent * total / 100.0); // may be 7.5
// after
int limit = (int) Math.floor(pageSizePercent * total / 100.0);
ps.setInt(1, limit);
Defensive patterns

Strategy: validation

Validate before calling

static int paginationParam(Object v) {
    if (!(v instanceof Number)) throw new IllegalArgumentException("pagination param must be Number");
    BigInteger i = new BigDecimal(v.toString()).toBigIntegerExact(); // throws early, clearly
    if (i.signum() < 0 || i.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) {
        throw new IllegalArgumentException("pagination param out of range: " + v);
    }
    return i.intValue();
}
// call paginationParam(limit) before ps.setXxx(...) and before executing federated query

Try / catch

try {
    rs = stmt.executeQuery();
} catch (final IllegalArgumentException ex) {
    if (ex.getMessage().contains("must be an integer")) { fixPaginationAndRetry(); } else { throw ex; }
}

Prevention

When it happens

Trigger: Binding a non-integral Number (float/double/BigDecimal with fraction) as a LIMIT or OFFSET parameter of a federated query; getIntegerValue is called from pagination parameter conversion during plan execution.

Common situations: Applications computing LIMIT dynamically (page size division, percentages) producing fractional values; passing Double parameters through PreparedStatement.setObject; upstream data producing 10.0-style decimals that carry fractions elsewhere.

Related errors


AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14). Data as JSON: /api/errors/d332254b3eb9693f. Report an issue: GitHub.