Skip to content

[BUG] basic_memory_diagnostics reports config.json, not effective settings — BASIC_MEMORY_* env overrides are invisible #1595

Description

@Hetox

Summary

basic_memory_diagnostics reads config.json off disk and prints it, but the running server's settings are BasicMemoryConfig(BaseSettings) with env_prefix="BASIC_MEMORY_", so every BASIC_MEMORY_* environment variable overrides that file at runtime. The tool therefore reports the file, not what the server is actually using — with no indication that the two can differ.

This matters most in containers and managed deployments, where env vars are the normal way to configure the server and config.json is whatever was auto-created on first start.

Reproduction

Server running with these in the environment (a Docker Compose deployment):

BASIC_MEMORY_SEMANTIC_EMBEDDING_MODEL: "sentence-transformers/paraphrase-multilingual-mpnet-base-v2"
BASIC_MEMORY_DEFAULT_SEARCH_TYPE: "vector"
BASIC_MEMORY_SEMANTIC_MIN_SIMILARITY: "0.49"

What the server actually loaded:

>>> from basic_memory.config import ConfigManager
>>> c = ConfigManager().load_config()
>>> c.semantic_embedding_model
'sentence-transformers/paraphrase-multilingual-mpnet-base-v2'
>>> c.default_search_type
'vector'
>>> c.semantic_min_similarity
0.49

Confirmed by the server's own startup log:

Semantic search: provider=fastembed, model=sentence-transformers/paraphrase-multilingual-mpnet-base-v2, dimensions=768

What config.json on disk says, and therefore what basic_memory_diagnostics reports:

{
  "semantic_embedding_model": "bge-small-en-v1.5",
  "default_search_type": null,
  "semantic_min_similarity": 0.55
}

All three values are wrong in the diagnostic output. Version 0.23.2.

Mechanism

src/basic_memory/mcp/tools/basic_memory_diagnostics.py:51-66 goes straight to the file:

config_file = resolve_data_dir() / CONFIG_FILE_NAME
config_exists = config_file.exists()

if config_exists:
    try:
        raw_config = json.loads(config_file.read_text(encoding="utf-8"))

while src/basic_memory/config_models.py:899-900 establishes the override layer:

model_config = SettingsConfigDict(
    env_prefix="BASIC_MEMORY_",

The file read is deliberate — the comment at basic_memory_diagnostics.py:49-50 explains that ConfigManager would create and chmod the directory, violating the tool's read-only contract. So this isn't an oversight in how the file is read; the gap is that the env layer is never represented at all.

Why it bites

The tool's stated purpose is "troubleshooting installations and gathering information for support requests". In exactly that situation — someone pastes diagnostics output into an issue — it silently reports a configuration the server is not running. An agent using it to confirm a config change will conclude the change did not take effect when it did, or vice versa.

It also makes the output self-inconsistent with the startup log, which does print effective values.

Suggested fix

The minimal change that keeps the read-only contract intact: don't load config at all, just show which BASIC_MEMORY_* variables are set, so the reader can see the file isn't the whole story.

env_overrides = {
    k: v for k, v in sorted(os.environ.items())
    if k.startswith("BASIC_MEMORY_")
}

rendered as its own section, values passed through the same redaction as the file dump (API keys arrive this way too — BASIC_MEMORY_SEMANTIC_EMBEDDING_API_KEY, BASIC_MEMORY_CLOUD_*), and with a one-line note in the Configuration section that env vars take precedence over the file.

That needs no config loading, creates no directories, and turns a misleading report into a complete one.

A fuller fix would print effective values by giving ConfigManager a read-only load path that skips directory creation, then dumping the resolved BasicMemoryConfig. That's strictly better output, but it's a larger change and touches the contract the existing comment is protecting — happy to go that way instead if you prefer.

I'm glad to open a PR for whichever shape you want.

Found on origin/main @ 3bf2d523.

Activity

  1. FBISiri commented on Sep 24, 2026

    @FBISiri
    Contributor

    One thing to watch in the minimal fix: "the same redaction as the file dump" doesn't work on raw env keys as-is.

    redact_config (src/basic_memory/redaction.py:112-131) matches exact lowercase field names — if k in SECRET_FIELDS / if k in URL_FIELDS. Env var names never match those, so passing the BASIC_MEMORY_* dict straight in is a no-op. I checked this against main @ 22d31e96 by loading redaction.py on its own and feeding it an env-shaped dict:

    raw env keys -> {"BASIC_MEMORY_SEMANTIC_EMBEDDING_API_KEY": "sk-live-SECRET", "BASIC_MEMORY_CLOUD_API_KEY": "cak-SECRET", "BASIC_MEMORY_DATABASE_URL": "postgresql://u:pw@db/bm", "BASIC_MEMORY_DEFAULT_SEARCH_TYPE": "vector"}
    normalized   -> {"database_url": "postgresql://***@db/bm", "default_search_type": "vector"}
    

    Stripping the prefix and lowercasing fixes it for config fields. But the prefix filter also picks up variables that aren't config fields at all, and those get past redaction even after normalizing. BASIC_MEMORY_API_KEY is one — bm ci tells users to set it as a secret (src/basic_memory/cli/commands/ci.py:136), and it's not a BasicMemoryConfig field:

    non-field    -> {"api_key": "bmk-SECRET"}
    

    So I'd scope the env section to BasicMemoryConfig.model_fields, normalized to field names before redaction. That's also exactly the set ConfigManager.load_config treats as overriding the file (src/basic_memory/config.py:113-118), so the section would show what actually took effect, not everything with the prefix. Any other BASIC_MEMORY_* vars could be listed by name only, without values.

    Caveat: I only exercised redaction.py (Python 3.9 here, the package needs 3.12), not the full MCP tool end to end.

  2. added this to the v0.24.0 milestone on Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions