#7490·mem0

Regression from #4805: _safe_deepcopy_config redacts the bool switch use_azure_credential, silently breaking config reconstruction

Author: passionworkeerCreated Sep 29, 2026Updated Sep 29, 2026
Labelssdk-pythonvector-store

Component

sdk-python (mem0/memory/main.py — _safe_deepcopy_config / _is_sensitive_field)

Description

TL;DR: _safe_deepcopy_config() redacts the boolean switch use_azure_credential because of the _credential suffix, which makes the pydantic reconstruction throw and silently degrade the config to a plain object. This is a regression introduced by #4805 — the field was explicitly protected in _RUNTIME_FIELDS by #4418, and #4805 removed that line and flipped the official test expectation to match.

Trigger path

  1. AzureMySQLConfig is constructed with a live connection_pool (a prebuilt pool is supported — the field is Optional[Any], mem0/configs/vector_stores/azure_mysql.py:29).
  2. Memory.__init__ calls _safe_deepcopy_config() on the vector store config (e.g. via the entity_store property, main.py:562 / main.py:2248, or the async telemetry path at main.py:2221).
  3. The bare deepcopy(config) fails on the live pool (TypeError: cannot pickle ...), so _safe_deepcopy_config falls into the reconstruction path: it copies field-by-field, setting every "sensitive" field to None.
  4. _is_sensitive_field("use_azure_credential") returns True — it is not in the 18-entry _SENSITIVE_FIELDS_EXACT list and not in _RUNTIME_FIELDS, so it matches purely on the _credential suffix. But the field is a bool switch (use DefaultAzureCredential or not), not a credential.
  5. Reconstructing AzureMySQLConfig(**fields) now fails validation:
pydantic_core._pydantic_core.ValidationError: 1 validation error for AzureMySQLConfig
use_azure_credential
  Input should be a valid boolean [type=bool_type, input_value=None, input_type=NoneType]
  1. The broad except Exception at main.py:294-298 swallows this, and the function returns type("Config", (), clone_dict)() — a plain object with no pydantic interface (model_dump, validation, typed fields all gone). (Side note: this fallback turns the dict into class attributes, so every such degraded object shares one dict — instances are not independent.)

  2. Downstream, VectorStoreFactory.create calls config.model_dump() (mem0/utils/factory.py:214) and raises AttributeError: 'Config' object has no attribute 'model_dump' — before load_class and before any network call.

Affected call sites on current main (94c3fe9f)

Location Path Effect
main.py:562 sync entity_store property AttributeError on first access (11 self.entity_store references go through it)
main.py:2248 async entity_store property same, async (13 references)
main.py:2221 async telemetry AttributeError at factory.py:214
main.py:532 sync telemetry not affected — the return value is overwritten at main.py:538; that dead call is what #5871 tracks

This is a regression from #4805, not a never-fixed gap

_RUNTIME_FIELDS was introduced by #4418 (merged 2026-03-19) and already contained "use_azure_credential", with the parameterized test expectation set to False ("not sensitive"). PR #4805 (merged 2026-04-14, "feat(oss): port v3 pipeline") removed exactly this one line and changed the test expectation at tests/memory/test_safe_deepcopy_config.py:169 to True, which fixed the wrong behavior into the test as the expected one:

commit 46b4b2e9 (2026-03-19, #4418): _RUNTIME_FIELDS contains "use_azure_credential"; test expects False
commit a488e190 (2026-04-14, #4805): line removed; test flipped to True
commit 94c3fe9f (current main):       still absent; test still expects True

Suggested fix (restores the pre-#4805 behavior)

Add "use_azure_credential" back to _RUNTIME_FIELDS and change the test expectation at tests/memory/test_safe_deepcopy_config.py:169 back to False. It is a bool switch and cannot carry a secret, so the allowlist is the semantically correct place — no heuristic (name-shape or type-based) is needed, and real credentials are unaffected (verified below). Not claiming this is the only possible fix, but it is the minimal one with git-history backing.

Boundary with existing reports: #3580 / #4418 are about http_auth on OpenSearch — same function, different field, not a duplicate. #5871 tracks the dead _safe_deepcopy_config call at main.py:532 — related location, unrelated defect. Nothing in the tracker covers use_azure_credential.

How You Verified This

On current origin/main (94c3fe9f238f3dbf29c9ce98643bd71eb13077cd), Python 3.12:

  1. _is_sensitive_field('use_azure_credential') returns True; the only matching rule is endswith('_credential') (not in _RUNTIME_FIELDS, not in _SENSITIVE_FIELDS_EXACT).
  2. Built a real AzureMySQLConfig with connection_pool=sqlite3.connect(":memory:") — a genuinely unpicklable live object, standing in for a prebuilt pool (no Azure service involved). The bare deepcopy fails with TypeError: cannot pickle 'sqlite3.Connection' object, which is the required precondition for the reconstruction path.
  3. After _safe_deepcopy_config, the clone is a plain Config object (type(clone).__mro__ == [Config, object]), use_azure_credential is None, password is None (expected — that one is a credential), and hasattr(clone, "model_dump") is False.
  4. Reconstructing the config from the redacted fields reproduces the exact ValidationError above (reproduced the reconstruction loop from main.py:279-295).
  5. Feeding the degraded clone into VectorStoreFactory.create raises AttributeError: 'Config' object has no attribute 'model_dump' at mem0/utils/factory.py:214 — before load_class, so no Azure/network access is involved in the failure.
  6. Verified the suggested fix restores behavior: with "use_azure_credential" back in _RUNTIME_FIELDS and the test expectation back to False, the full tests/memory/test_safe_deepcopy_config.py suite is green (99 items including 5 new regression tests) and a real credential field (password) is still redacted.
  7. Checked the suffix blast radius with an AST scan over all of mem0/configs/: of 25 fields that match either the exact list or the suffix list, only one is matched via a suffix, and it is this bool field. No other non-credential scalar is affected.
  8. Collision check: searched open/closed issues and PRs (use_azure_credential, safe_deepcopy_config, credential suffix, redact config, entity_store deepcopy, …, plus a full scan of the 8000-item issue/PR list) — no existing report covers this.

AI Assistance

AI-generated (an agent wrote most or all of this report): the reproduction, the AST blast-radius scan, the git regression history, and the fix verification above were produced by an AI agent working against a local clone at 94c3fe9f; every claim listed under "How You Verified This" comes from real runs logged locally, and the finding was reviewed and confirmed by the contributor. No cloud Azure service was used — the failure reproduces entirely offline.