Skip to content

fix(ts-sdk): resolve SQLite db paths correctly in OSS mode#4307

Merged
deshraj merged 3 commits intomainfrom
fix/sqlite-path-handling
Mar 12, 2026
Merged

fix(ts-sdk): resolve SQLite db paths correctly in OSS mode#4307
deshraj merged 3 commits intomainfrom
fix/sqlite-path-handling

Conversation

@utkarsh240799
Copy link
Copy Markdown
Contributor

@utkarsh240799 utkarsh240799 commented Mar 12, 2026

Description

Fixes SQLite path handling bugs in OSS mode for the TypeScript SDK.

Fixes #4290
Fixes #4080
Fixes #4096

Problem

There are two SQLite path bugs in OSS mode that cause failures in daemon/service/container environments:

Bug 1: historyDbPath is silently ignored

ConfigManager.mergeConfig() always spreads DEFAULT_MEMORY_CONFIG.historyStore (which hardcodes historyDbPath: "memory.db") into the merged config. Since spreading undefined over the default is a no-op, historyStore is always truthy after merging. The Memory constructor then always takes the historyStore branch, making the top-level historyDbPath dead code.

// User sets this...
const m = new Memory({ historyDbPath: "/data/history.db" });

// ...but mergeConfig always produces this:
historyStore: { provider: "sqlite", config: { historyDbPath: "memory.db" } }  // default wins

// Memory constructor always takes this branch (historyStore is always truthy):
this.db = HistoryManagerFactory.create(this.config.historyStore.provider, this.config.historyStore);
// → opens "memory.db" relative to CWD, ignoring the user's "/data/history.db"

Bug 2: vector_store.db hardcoded to process.cwd()

MemoryVectorStore defaults to path.join(process.cwd(), "vector_store.db"), which fails when CWD is / or not writable — common in LaunchAgent, systemd, and container environments.

Solution

  • Propagate historyDbPath into historyStore.config.historyDbPath during config merging with correct precedence: explicit historyStore.config > top-level historyDbPath shorthand > default memory.db
  • Only spread default sqlite config for sqlite providers — prevents historyDbPath: "memory.db" from leaking into supabase/other provider configs
  • Default vector store path to ~/.mem0/vector_store.db instead of process.cwd()/vector_store.db
  • Emit a migration warning when an existing vector_store.db is found at the old CWD-based location
  • Auto-create parent directories for file-backed SQLite databases before opening them
  • Remove dead code in the Memory constructor — the defaultConfig fallback was unreachable since historyStore is always populated after config merging
  • Add dbPath to VectorStoreConfig interface and zod schema

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (does not change functionality, e.g. code style improvements, linting)
  • Documentation update

How Has This Been Tested?

  • Unit Test
  • Test Script (please provide)

Commands run locally:

cd mem0-ts
npm test -- --runInBand \
  src/oss/src/tests/sqlite-path-resolution.test.ts \
  src/oss/src/tests/sqlite-backward-compat.test.ts \
  src/oss/src/tests/better-sqlite3-migration.test.ts

65 tests total — all passing (41 new + 24 existing, 0 regressions).

New tests: sqlite-path-resolution.test.ts — 19 tests

Config merging (6):

Test What it verifies
propagates top-level historyDbPath into historyStore.config mergeConfig({ historyDbPath }) populates historyStore.config.historyDbPath and SQLiteManager creates the DB at the nested path
explicit historyStore.config.historyDbPath takes precedence over top-level When both are set, the more specific historyStore.config wins
preserves default memory.db when nothing is provided Default behavior unchanged
respects only historyStore.config when top-level is absent Direct historyStore.config works without shorthand
does not leak historyDbPath into non-sqlite providers Supabase config doesn't get default historyDbPath: "memory.db"
disableHistory does not prevent historyStore config from merging Config merging is independent of the disable flag

SQLiteManager (3):

Test What it verifies
creates nested parent directories and writes to the DB ensureSQLiteDirectory creates a/b/c/ before opening
end-to-end: mergeConfig + SQLiteManager at configured path Full flow from user config → DB file at correct location
works with :memory: without attempting directory creation Special paths are not modified

MemoryVectorStore (5):

Test What it verifies
uses ~/.mem0/vector_store.db by default New default location works (mocked homedir)
respects explicit dbPath config vectorStore.config.dbPath overrides the default
works when CWD is read-only chmod 555 CWD doesn't prevent initialization
emits migration warning when old CWD-based vector_store.db exists Users with existing data are warned about the location change
does NOT emit migration warning when dbPath is explicitly set No false warnings when path is user-controlled

Utilities (5):

Test What it verifies
ensureSQLiteDirectory creates nested directories recursive: true works
skips :memory: No filesystem side effects for in-memory DBs
skips file: URIs SQLite URI paths are not modified
skips empty string Edge case handled
getDefaultVectorStoreDbPath returns path under homedir/.mem0 Default path is correct

New tests: sqlite-backward-compat.test.ts — 22 tests

Category Tests What they verify
Config defaults (8) empty config, explicit historyStore workaround, disableHistory, supabase provider, embedder/llm/vectorStore/graphStore pass-through, customPrompt, version All existing config patterns produce identical output
SQLiteManager (4) relative path, absolute path, :memory:, reset+re-use All existing SQLiteManager usage patterns still work
MemoryVectorStore (6) explicit dbPath, full CRUD API, dimension mismatch throws, default dimension 1536, search with filters All existing MemoryVectorStore API behavior preserved
VectorStoreConfig type (2) config without dbPath, config with client instance No required-field breakage from adding dbPath
ensureSQLiteDirectory (2) idempotent on existing dirs, trailing slash handling No side effects on valid existing paths

Existing tests: better-sqlite3-migration.test.ts — 24 tests, all passing

No regressions.

Note: npm test -- --runInBand for the entire mem0-ts package still hits pre-existing failures in unrelated integration-style tests (src/client/tests/memoryClient.test.ts, src/oss/tests/memory.test.ts) that require external services / outdated call signatures. This PR does not modify those areas.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules
  • I have checked my code and corrected any misspellings

Maintainer Checklist

utkarsh240799 and others added 3 commits March 12, 2026 13:45
Propagate top-level historyDbPath into historyStore.config so it
survives config merging, default the memory vector store to
~/.mem0/vector_store.db instead of process.cwd(), auto-create parent
directories for file-backed SQLite databases, and remove dead code
in the Memory constructor.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevent default sqlite historyDbPath from leaking into non-sqlite
providers during config merging. Consolidate and expand test coverage
to 19 tests: config precedence, non-sqlite isolation, migration
warning, explicit dbPath, read-only CWD, and utility edge cases.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Verify that all existing usage patterns continue to work:
- empty config defaults, explicit historyStore workaround, disableHistory
- supabase/non-sqlite provider configs preserved
- embedder, llm, vectorStore, graphStore, customPrompt pass-through
- SQLiteManager with relative, absolute, and :memory: paths
- MemoryVectorStore full CRUD API, dimension checks, filters
- VectorStoreConfig with/without dbPath, client instance pass-through
- ensureSQLiteDirectory idempotency

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@deshraj deshraj merged commit 5b3acf4 into main Mar 12, 2026
3 checks passed
utkarsh240799 added a commit that referenced this pull request Mar 14, 2026
Includes SQLite path resolution fixes from PR #4307:
- Default vector_store.db location changed from process.cwd() to ~/.mem0/
- historyDbPath config propagation fix
- Auto-create parent directories for SQLite DB files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
jamebobob pushed a commit to jamebobob/mem0-vigil-recall that referenced this pull request Mar 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants