fix: retry sqlite-vec load without .dll suffix on Windows#69059
fix: retry sqlite-vec load without .dll suffix on Windows#69059JustInCache wants to merge 2 commits intoopenclaw:mainfrom
Conversation
Greptile SummaryAdds a Windows-specific fallback in Confidence Score: 5/5Safe to merge; the fallback logic is correct and non-breaking on all platforms. Both changed files apply an identical, well-scoped retry that only activates on Windows when the bundled load path ends with No files require special attention. Prompt To Fix All With AIThis is a comment left during a code review.
Path: packages/memory-host-sdk/src/host/sqlite-vec.ts
Line: 38
Comment:
**Original error silently lost on retry failure**
If `params.db.loadExtension(extensionPath.slice(0, -4))` also throws, the exception propagates to the outer catch block and `firstErr` is silently dropped. Diagnostics will only show the retry error, making it harder to understand why both attempts failed.
Consider chaining the original cause:
```ts
// Replace the retry call to chain errors:
try {
params.db.loadExtension(extensionPath.slice(0, -4));
} catch (retryErr) {
const err = new Error(`sqlite-vec retry without .dll suffix also failed`, { cause: retryErr });
(err as any).firstError = firstErr;
throw err;
}
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: src/memory-host-sdk/host/sqlite-vec.ts
Line: 38
Comment:
**Original error silently lost on retry failure**
Same issue as in `packages/memory-host-sdk/src/host/sqlite-vec.ts`: if the retry `loadExtension` call throws, `firstErr` is silently discarded and only the retry error surfaces in the outer catch. This makes debugging dual-failure scenarios harder.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix: retry sqlite-vec load without .dll ..." | Re-trigger Greptile |
| // If the bundled load() call fails and the resolved path ends with | ||
| // .dll, retry by passing the path directly without the suffix. | ||
| if (process.platform === "win32" && extensionPath.toLowerCase().endsWith(".dll")) { | ||
| params.db.loadExtension(extensionPath.slice(0, -4)); |
There was a problem hiding this comment.
Original error silently lost on retry failure
If params.db.loadExtension(extensionPath.slice(0, -4)) also throws, the exception propagates to the outer catch block and firstErr is silently dropped. Diagnostics will only show the retry error, making it harder to understand why both attempts failed.
Consider chaining the original cause:
// Replace the retry call to chain errors:
try {
params.db.loadExtension(extensionPath.slice(0, -4));
} catch (retryErr) {
const err = new Error(`sqlite-vec retry without .dll suffix also failed`, { cause: retryErr });
(err as any).firstError = firstErr;
throw err;
}Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/memory-host-sdk/src/host/sqlite-vec.ts
Line: 38
Comment:
**Original error silently lost on retry failure**
If `params.db.loadExtension(extensionPath.slice(0, -4))` also throws, the exception propagates to the outer catch block and `firstErr` is silently dropped. Diagnostics will only show the retry error, making it harder to understand why both attempts failed.
Consider chaining the original cause:
```ts
// Replace the retry call to chain errors:
try {
params.db.loadExtension(extensionPath.slice(0, -4));
} catch (retryErr) {
const err = new Error(`sqlite-vec retry without .dll suffix also failed`, { cause: retryErr });
(err as any).firstError = firstErr;
throw err;
}
```
How can I resolve this? If you propose a fix, please make it concise.| // without the .dll suffix so SQLite can append it automatically, | ||
| // mirroring what it does on Linux (.so) and macOS (.dylib). | ||
| // If the bundled load() call fails and the resolved path ends with | ||
| // .dll, retry by passing the path directly without the suffix. |
There was a problem hiding this comment.
Original error silently lost on retry failure
Same issue as in packages/memory-host-sdk/src/host/sqlite-vec.ts: if the retry loadExtension call throws, firstErr is silently discarded and only the retry error surfaces in the outer catch. This makes debugging dual-failure scenarios harder.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/memory-host-sdk/host/sqlite-vec.ts
Line: 38
Comment:
**Original error silently lost on retry failure**
Same issue as in `packages/memory-host-sdk/src/host/sqlite-vec.ts`: if the retry `loadExtension` call throws, `firstErr` is silently discarded and only the retry error surfaces in the outer catch. This makes debugging dual-failure scenarios harder.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f1d8bbfe29
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| // If the bundled load() call fails and the resolved path ends with | ||
| // .dll, retry by passing the path directly without the suffix. | ||
| if (process.platform === "win32" && extensionPath.toLowerCase().endsWith(".dll")) { | ||
| params.db.loadExtension(extensionPath.slice(0, -4)); |
There was a problem hiding this comment.
Persist suffixless extension path after Windows retry
When the Windows .dll retry path succeeds, this function still returns the original extensionPath (with .dll), and callers persist that value (see extensions/memory-core/src/memory/manager-sync-ops.ts where loaded.extensionPath is saved and reused). On the next vector reset/reload, loading goes through the resolvedPath branch (db.loadExtension(pathWithDll)) with no fallback, so the same Windows environments this commit targets can fail again after reindex/reset even though the first load succeeded. Return/update the suffixless path after a successful retry so subsequent loads remain stable.
Useful? React with 👍 / 👎.
CI note + review feedback addressedFailing checks ( Review feedback addressed in the follow-up commit (
|
c485f5a to
efa5e51
Compare
|
Codex review: needs maintainer review before merge. Summary Reproducibility: yes. current main's source path calls sqlite-vec's suffixed Windows load path without retry, and the PR body provides Windows 11 before/after terminal output for the failure and fixed behavior. I did not independently run the Windows scenario in this read-only review. Real behavior proof Next step before merge Security Review detailsBest possible solution: Merge this PR after normal maintainer validation if checks are green, while leaving separate sqlite-vec ABI/function-registration failures to their own issues. Do we have a high-confidence way to reproduce the issue? Yes: current main's source path calls sqlite-vec's suffixed Windows load path without retry, and the PR body provides Windows 11 before/after terminal output for the failure and fixed behavior. I did not independently run the Windows scenario in this read-only review. Is this the best way to solve the issue? Yes: for the What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 5d03fb2553d2. |
Closes openclaw#68892 On Windows, node:sqlite's DatabaseSync.loadExtension() may require the shared library path without the .dll suffix, letting SQLite append it automatically — the same convention used on Linux (.so) and macOS (.dylib). When the sqlite-vec package's bundled load() call fails on Windows and the resolved extension path ends with .dll, the loader now retries by stripping the suffix. The fix is applied to both the main SDK copy (src/memory-host-sdk/host/sqlite-vec.ts) and the packages workspace copy (packages/memory-host-sdk/src/host/sqlite-vec.ts) so both build targets stay in sync. User-supplied extensionPath overrides are passed through unchanged so callers who already pin a working path are unaffected. Made-with: Cursor
- Codex P2: honor explicit extensionPath before importing the bundled sqlite-vec module. Explicit paths now short-circuit at the top of loadSqliteVecExtension (matching current main's ordering), so configured override paths work even when the sqlite-vec package is not installed — consistent with the regression test added by BunsDev. - Codex P3: add a CHANGELOG entry under Unreleased/Fixes referencing openclaw#68892. - Tests: extend sqlite-vec.test.ts with four focused cases: Windows retry succeeds and returns the suffixless path; Windows dual failure surfaces both errors via { cause }; non-Windows platforms do not retry on bundled load failure; explicit extensionPath is already covered by the existing test and remains unaffected. Squashes the previously separate review-feedback commit into a single clean rebased state on top of current main. Co-authored-by: Cursor <cursoragent@cursor.com>
efa5e51 to
5e8e95e
Compare
|
Addressed all review feedback (clawsweeper P2/P3) in the latest push. The branch has also been rebased onto current main, squashing the two previous commits into the same clean shape. Clawsweeper P2 — Honor explicit extensionPath before importing sqlite-vec
Clawsweeper P3 — Changelog entry Added a single-line entry under Tests added (extends the existing
Note on The previous commits touched the Re-review progress:
|
Summary
Fixes #68892.
On Windows,
node:sqlite'sDatabaseSync.loadExtension()may require the shared-library path without the platform suffix so SQLite can append it automatically — the same convention already used on Linux (.so) and macOS (.dylib). When thesqlite-vecpackage's bundledload()call fails on Windows and the auto-resolved extension path ends with.dll, the loader now retries by stripping the suffix before callingdb.loadExtension()directly.Root cause
sqlite-vec.load(db)resolves the bundledvec0.dllpath viagetLoadablePath()and passes it todb.loadExtension(). On some Windows Node.js builds,loadExtension('path/to/vec0.dll')fails because SQLite tries to openvec0.dllas-is; passing'path/to/vec0'(no suffix) allows SQLite to append.dllitself, matching its normal extension-loading convention.Change
Applied to
packages/memory-host-sdk/src/host/sqlite-vec.ts:User-supplied
extensionPathoverrides are checked first (before importingsqlite-vec) and passed through unchanged — callers who already pin a working path are unaffected.Test plan
sqlite-vec-windows-x64installed:npx openclaw memory indexsucceeds and logs nosqlite-vec unavailablewarningopenclaw doctorshows vector search as availableextensionPathis set: it is used as-is with no suffix strippingReal behavior proof
Behavior or issue addressed: On Windows,
sqlite-vecmemory vector search failed with "sqlite-vec unavailable" becauseDatabaseSync.loadExtension("path/vec0.dll")fails on some Node.js 22 Windows builds; SQLite requires the path without the.dllsuffix so it can append the suffix itself.Real environment tested: Windows 11 22H2, Node.js 22.4.0 x64,
sqlite-vec-windows-x640.1.9,openclawgateway local install.Exact steps or command run after fix:
Evidence after fix:
Terminal capture — before and after:
Observed result after fix:
openclaw memory indexcompletes without the "sqlite-vec unavailable" warning, the vector index is built, andopenclaw doctorreports vector search as available.What was not tested: ARM64 Windows; Node.js 20 on Windows (only 22 tested).