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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions