t8y2/dbx · error · IllegalArgumentException
Query timeout cannot be negative: " + timeoutSecs
Error message
Query timeout cannot be negative: " + timeoutSecs
What it means
OceanBaseOracleAgent validates the query timeout before building the ALTER SESSION statement. A negative timeoutSecs would produce a meaningless negative microsecond session timeout, so queryTimeoutSql throws IllegalArgumentException. 0 is allowed and means unlimited (UNLIMITED_QUERY_TIMEOUT_MICROS).
Source
Thrown at agents/drivers/oceanbase-oracle/src/main/java/com/dbx/agent/oceanbaseoracle/OceanBaseOracleAgent.java:121
}
}
@Override
protected Object resultValue(ResultSet rs, int index, int sqlType) {
switch (sqlType) {
case Types.BINARY:
case Types.VARBINARY:
case Types.LONGVARBINARY:
case Types.BLOB:
return unchecked(() -> JdbcExecutor.stringResultValue(rs, index, sqlType));
default:
return super.resultValue(rs, index, sqlType);
}
}
static String queryTimeoutSql(int timeoutSecs) {
if (timeoutSecs < 0) {
throw new IllegalArgumentException("Query timeout cannot be negative: " + timeoutSecs);
}
long timeoutMicros = timeoutSecs == 0
? UNLIMITED_QUERY_TIMEOUT_MICROS
: timeoutSecs * MICROS_PER_SECOND;
return "ALTER SESSION SET ob_query_timeout = " + timeoutMicros;
}
private static boolean isReadOnlyTransactionError(SQLException error) {
Deque<Throwable> pending = new ArrayDeque<>();
Set<Throwable> seen = Collections.newSetFromMap(new IdentityHashMap<>());
pending.add(error);
while (!pending.isEmpty()) {
Throwable current = pending.removeFirst();
if (!seen.add(current)) {
continue;
}
if (current instanceof SQLException) {
SQLException sqlError = (SQLException) current;View on GitHub (pinned to c0390bff16)
Solutions
- Pass 0 for unlimited instead of a negative value, or clamp: Math.max(0, timeoutSecs).
- Translate the driver-independent -1 sentinel to 0 at the call site before invoking the hooks.
- Fix the config/env source feeding the timeout so it never yields negatives.
Example fix
// before agent.beforeQueryExecution(sql, timeoutSecs); // timeoutSecs = -1 // after agent.beforeQueryExecution(sql, timeoutSecs < 0 ? 0 : timeoutSecs); // 0 = unlimited
Defensive patterns
Strategy: validation
Validate before calling
int safeTimeout(int timeoutSecs) {
if (timeoutSecs < 0) throw new IllegalArgumentException("Pass 0 for unlimited, not a negative value: " + timeoutSecs);
return timeoutSecs;
} Try / catch
try {
agent.beforeQueryExecution(sql, timeoutSecs);
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Query timeout cannot be negative")) {
agent.beforeQueryExecution(sql, 0); // 0 = unlimited
} else throw e;
} Prevention
- Remember this driver's convention: 0 = unlimited; never forward -1 sentinels.
- Clamp values from config/env with Math.max(0, value) before use.
- Add a unit test for queryTimeoutSql boundary values (-1, 0, large).
When it happens
Trigger: Calling queryTimeoutSql (directly or via beforeQueryExecution / beforePooledConnectionReturn hooks) with timeoutSecs < 0, e.g. passing a sentinel like -1 as 'default' instead of 0 for unlimited.
Common situations: Config files where the timeout field defaults to -1 meaning 'unset' and the value is forwarded unconverted; subtracting timestamps to compute a remaining timeout that has already elapsed; mixing conventions where -1 means unlimited in another driver but 0 means unlimited here.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Unsupported object type: " + objectType
- sql is required
- table read requires a SELECT query
- invalid Hive browserResponseTimeout %q: expected positive se
- invalid Hive browserResponseTimeout %q: expected positive se
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/233bf1a2027326b3.
Report an issue: GitHub.