Skip to content

fix(openclaw): propagate historyDbPath into historyStore to prevent SQLITE_CANTOPEN crash loop#4160

Closed
nyrosveil wants to merge 2 commits intomem0ai:mainfrom
nyrosveil:fix/openclaw-history-db-path
Closed

fix(openclaw): propagate historyDbPath into historyStore to prevent SQLITE_CANTOPEN crash loop#4160
nyrosveil wants to merge 2 commits intomem0ai:mainfrom
nyrosveil:fix/openclaw-history-db-path

Conversation

@nyrosveil
Copy link
Copy Markdown

@nyrosveil nyrosveil commented Feb 28, 2026

Description

Fixes a bug in the OpenClaw plugin where setting oss.historyDbPath in the config had no effect, causing a SQLITE_CANTOPEN crash loop when running as a macOS LaunchAgent (service).

Root cause

mem0ai's DEFAULT_MEMORY_CONFIG always initialises historyStore.config.historyDbPath to "memory.db" (a relative path). The Memory constructor always prefers historyStore over the top-level historyDbPath field when historyStore is present — and it is always present because it is merged from defaults. So the user-configured historyDbPath was never actually used.

When the OpenClaw gateway runs as a LaunchAgent with no WorkingDirectory set (the default install), process.cwd() resolves to /. The relative "memory.db" then becomes /memory.db, which is unwritable on macOS (System Integrity Protection), causing:

[openclaw] Uncaught exception: Error: SQLITE_CANTOPEN: unable to open database file

on every before_agent_start hook — crashing the gateway in a continuous restart loop on each incoming message.

Fix

  • Extracts the OSS Memory config-building logic from OSSProvider._init() into an exported buildOSSMemoryConfig() helper
  • When historyDbPath is explicitly set, also sets historyStore to override the default, ensuring the Memory constructor uses the correct absolute path

Fixes # (no existing issue — discovered and fixed in production)

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Refactor (does not change functionality — extraction of config builder for testability)

How Has This Been Tested?

Unit tests (openclaw/tests/oss-history-db.test.ts, 13 tests via vitest):

  • Base config shape with no/empty ossConfig
  • Passthrough of embedder, vectorStore, and llm provider configs
  • historyDbPath absent → historyStore not set
  • historyDbPath present → both historyDbPath and historyStore set correctly
  • historyStore.config.historyDbPath matches the configured path (regression test)
  • resolvePath applied to both historyDbPath and historyStore
✓ tests/oss-history-db.test.ts (13 tests)
Test Files  1 passed (1)
     Tests  13 passed (13)

Manual (production verification on macOS with gateway running as LaunchAgent):

  • Without fix: gateway crashed with SQLITE_CANTOPEN on every message

  • With fix: history.db created at the specified absolute path, gateway runs stably

  • Unit Test

  • Test Script (manual — described above)

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

When `oss.historyDbPath` is set in the plugin config, the value was
correctly assigned to `config.historyDbPath` but was silently ignored
at runtime. The cause: `mem0ai`'s `DEFAULT_MEMORY_CONFIG` always
initialises `historyStore.config.historyDbPath` to `"memory.db"` (a
relative path), and the Memory constructor always prefers `historyStore`
over the top-level `historyDbPath` field when `historyStore` is present.

Since `historyStore` is always truthy (merged from defaults), the
explicit path set by the user was never used. When the gateway runs
as a LaunchAgent with no `WorkingDirectory`, `process.cwd()` is `/`
and `"memory.db"` resolves to `/memory.db` — unwritable on macOS due
to SIP — causing `SQLITE_CANTOPEN` on every `before_agent_start` hook,
crashing the gateway in a restart loop.

Fix: when `historyDbPath` is set, also set `historyStore` explicitly
so the Memory constructor uses the correct absolute path.
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Feb 28, 2026

CLA assistant check
All committers have signed the CLA.

… fix

Extracts the OSS Memory config-building logic from OSSProvider._init()
into an exported buildOSSMemoryConfig() helper, making the fix directly
unit-testable without requiring mem0ai/oss to be instantiated.

Adds 13 tests in openclaw/tests/oss-history-db.test.ts (vitest) covering:
- Base config shape with no/empty ossConfig
- Passthrough of embedder, vectorStore, and llm provider configs
- historyDbPath absent → historyStore not set
- historyDbPath present → both historyDbPath and historyStore set
- historyStore.config.historyDbPath matches the configured path (regression)
- resolvePath applied to both historyDbPath and historyStore
@jonasstenberg
Copy link
Copy Markdown

Please prioritize this. 👍

@utkarsh240799
Copy link
Copy Markdown
Contributor

Thanks for the thorough contribution and testing! This is no longer needed — PR #4307 (merged) fixes the root cause upstream in the mem0ai SDK. mergeConfig() now correctly propagates top-level historyDbPath into historyStore.config.historyDbPath, so the plugin-side workaround is redundant. Closing in favor of the upstream fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants