quarkusio/quarkus · error · RedisKeyNotFoundException
The key `" + key + "` does not exist
Error message
The key `" + key + "` does not exist
What it means
decodeExpireResponse() interprets the reply of Redis EXPIRE-style commands. Redis returns -2 when the key does not exist; the Quarkus Redis client translates that into RedisKeyNotFoundException carrying the key name, instead of returning a misleading -2. This lets callers distinguish 'key gone' from a real expiration failure.
Source
Thrown at extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractKeyCommands.java:140
cmd.put(marshaller.encode(key));
cmd.put(timestamp);
cmd.putArgs(expireArgs);
return execute(cmd);
}
Uni<Response> _expireat(K key, Instant timestamp, ExpireArgs expireArgs) {
return _expireat(key, timestamp.getEpochSecond(), expireArgs);
}
Uni<Response> _expiretime(K key) {
nonNull(key, "key");
return execute(RedisCommand.of(EXPIRETIME).put(marshaller.encode(key)));
}
long decodeExpireResponse(K key, Response r) {
long res = r.toLong();
if (res == -2) {
throw new RedisKeyNotFoundException(new String(marshaller.encode(key), StandardCharsets.UTF_8));
}
return res;
}
Uni<Response> _keys(String pattern) {
nonNull(pattern, "pattern");
if (pattern.isBlank()) {
return Uni.createFrom().failure(new IllegalArgumentException("`pattern` must not be blank"));
}
return execute(RedisCommand.of(Command.KEYS).put(pattern));
}
List<K> decodeKeys(Response response) {
return marshaller.decodeAsList(response, typeOfKey);
}
Uni<Response> _move(K key, long db) {View on GitHub (pinned to e1c734241f)
Solutions
- Handle RedisKeyNotFoundException in your Uni failure consumer and treat it as a non-fatal 'key missing' case.
- Check key existence first with the key commands (e.g. exists/key) if the race matters to your logic.
- Verify the key name/serialization matches what was actually written (prefixes, marshaller).
Example fix
// before
redis.expire(key, Duration.ofMinutes(5)).await().indefinitely();
// after
try {
redis.expire(key, Duration.ofMinutes(5)).await().indefinitely();
} catch (RedisKeyNotFoundException e) {
// key no longer exists; skip TTL update
} Defensive patterns
Strategy: try-catch
Validate before calling
Boolean exists = redis.withConnection(c -> c.key().exists(key)).await().indefinitely();
Try / catch
try {
redis.expire(key, ttl).await().indefinitely();
} catch (RedisKeyNotFoundException e) {
// key does not exist; handle gracefully
} Prevention
- Treat 'key missing' as an expected outcome of EXPIRE-style commands.
- Centralize key naming/prefixing to avoid key typos.
- Check existence with key().exists() when the race with deletions matters.
When it happens
Trigger: Calling expire/getExpire/pexpire-style key commands (e.g. ReactiveRedisDataSource.expire(key, ttl)) on a key that has been deleted or never existed; the server reply is -2.
Common situations: Race where another consumer/service deletes the key between existence check and EXPIRE; TTL already elapsed before the call; wrong key spelling or missing prefix in serialized key names.
Related errors
- The Reactive Redis Client must be injected
- `count` must be strictly positive
- Redis host not configured - you must either configure 'quark
- Multiple Redis hosts supplied for non-clustered configuratio
- Unable to find redis host provider identified with " + name
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/1ab38abe9aad3594.
Report an issue: GitHub.