Skip to content

HashModel.save() crashes with unknown command 'HTTL' on Redis < 7.4 when redis-py ≥ 5.1.0 #829

@Roman513

Description

@Roman513

Description

HashModel.save() raises ResponseError: unknown command 'HTTL' on any Redis server older than 7.4.

The root cause is supports_hash_field_expiration() checking only the redis-py client version, not the Redis server version:

# redis_om/model/model.py
def supports_hash_field_expiration():
    try:
        import redis as redis_lib
        version_str = getattr(redis_lib, "__version__", "0.0.0")
        version_parts = tuple(int(x) for x in version_str.split(".")[:3])
        if version_parts >= (5, 1, 0):
            return hasattr(redis_lib.asyncio.Redis, "hexpire")  # always True with redis-py 5.x
        return False
    except (ValueError, AttributeError):
        return False

With redis-py >= 5.1.0 installed, this always returns True, so save() unconditionally calls HTTL — a command only available since Redis 7.4.

Reproduction

from redis_om.model.model import supports_hash_field_expiration
import redis as redis_lib

print("redis-py version:", redis_lib.__version__)
# redis-py version: 5.3.1

print("supports_hash_field_expiration():", supports_hash_field_expiration())
# supports_hash_field_expiration(): True   ← wrong: only checks client

conn = redis_lib.Redis.from_url("redis://localhost:6379/0")
print("Redis server version:", conn.info("server").get("redis_version"))
# Redis server version: 6.2.18            ← server doesn't support HTTL

Then calling .save() on any HashModel:

redis.exceptions.ResponseError: unknown command `HTTL`, with args beginning with:
`myapp:mymodel:some-key`, `FIELDS`, `2`, `field1`, `field2`

Expected behaviour

supports_hash_field_expiration() should verify the connected Redis server is ≥ 7.4 before returning True. Checking only the client library version is insufficient.

Environment

  • redis-om: 1.1.0
  • redis-py: 5.3.1
  • Redis server: 6.2.18 (also reproducible on any Redis < 7.4, including Azure Cache for Redis)
  • Python: 3.13

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions