Skip to content

[BUG] Empty ~/basic-memory directory recreated on every config load (mkdir side effect in config validator) #1029

Description

@MHoroszowski

Summary

On every config load, Basic Memory recreates an empty ~/basic-memory directory even when the user has configured a completely different project path (e.g. ~/Documents/BasicMemory) and no BASIC_MEMORY_HOME is set. The directory reappears after nearly every bm command and each MCP server startup.

The recreated directory is always empty and unused — real notes/DB live at the correctly-configured path — so this is a cosmetic-but-persistent surprise rather than data loss.

Reproduction

Config (~/.basic-memory/config.json) points main at a custom path:

"projects": { "main": { "path": "/Users/me/Documents/BasicMemory", "mode": "local" } },
"default_project": "main"

Then:

rm -rf ~/basic-memory
bm reindex          # or: bm project list  (anything that loads config)
ls -d ~/basic-memory   # -> exists again, empty
bm --version        # does NOT recreate it (never loads config)

bm project list still correctly reports only main -> ~/Documents/BasicMemory; the ~/basic-memory dir is a phantom.

Root cause

The culprit is a filesystem side effect in a Pydantic validator, triggered by a throwaway config instance. In src/basic_memory/config.py (line numbers from current main):

  1. ConfigManager.load_config() builds a throwaway config only to read env-var defaults, passing no file data (~line 612):
    env_config = BasicMemoryConfig()
    env_dict = env_config.model_dump()
  2. With no file data and BASIC_MEMORY_HOME unset, model_post_init injects a default project pointing at ~/basic-memory (~lines 505-509):
    if not self.projects:
        self.projects["main"] = ProjectEntry(
            path=str(Path(os.getenv("BASIC_MEMORY_HOME", Path.home() / "basic-memory"))))
  3. The @model_validator(mode="after") ensure_project_paths_exists then mkdirs that path as a side effect (~line 545):
    path.mkdir(parents=True)

So merely instantiating BasicMemoryConfig() to inspect env defaults writes a directory to disk — against a default path the user never selected.

Suggested fixes (any one breaks the chain)

  • Don't create directories inside a model_validator. Move ensure_project_paths_exists's mkdir into an explicit initialization step (the code path that actually commits/uses a project), so constructing a config has no filesystem effect.
  • Or make the env-default probe side-effect-free — read env fields without triggering model_post_init/after-validators (e.g. a dedicated defaults helper), rather than constructing a full BasicMemoryConfig().

Environment

  • basic-memory 0.22.1 (latest release; Homebrew install, Python 3.14)
  • macOS
  • BASIC_MEMORY_HOME unset; single local project at a custom path

Workaround

Setting export BASIC_MEMORY_HOME=<real vault path> stops the recreation, because the throwaway default then points at an already-existing directory and the mkdir becomes a no-op.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Fields

    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