fix(memory-wiki): bridge status crashes on malformed memory-plugin artifacts and ignores readMemoryArtifacts=false#100900
Conversation
…yArtifacts in status Two crashes when a memory plugin misbehaves in bridge mode: - listActiveMemoryPublicArtifacts sorted plugin-returned artifacts without validating them; an artifact missing any of the string fields the comparator dereferences (kind, workspaceDir, relativePath, absolutePath, contentType) crashed wiki status and every other bridge consumer with "Cannot read properties of undefined (reading 'localeCompare')". @mem0/openclaw-mem0 <= 1.0.14 shipped record-shaped artifacts with none of those fields, typed against a drifted SDK stub. Validate the shape, drop malformed entries (and non-array listings), and warn once naming the offending plugin -- the same treatment agentIds already got. - resolveMemoryWikiStatus gated artifact counting on vaultMode/enabled but not bridge.readMemoryArtifacts, so the wiki.status gateway method still enumerated artifacts (and hit the crash above) with the flag off, even though the sync path (bridge.ts) and CLI gateway routing honor it. The documented workaround therefore never worked for the wiki_status agent tool. Add the flag to the gate; the count reports null when imports are disabled, matching non-bridge modes.
|
Codex review: needs maintainer review before merge. Reviewed July 6, 2026, 10:22 AM ET / 14:22 UTC. Summary PR surface: Source +31, Tests +86. Total +117 across 4 files. Reproducibility: yes. Current main has a source-reproducible path: plugin-returned public artifacts are sorted with unguarded string field dereferences, and status enumeration ignores Review metrics: 1 noteworthy metric.
Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Next step before merge
Security Review detailsBest possible solution: Land the narrow host-boundary hardening with the added regression tests, while leaving the mem0-specific plugin contract repair to mem0ai/mem0#6114. Do we have a high-confidence way to reproduce the issue? Yes. Current main has a source-reproducible path: plugin-returned public artifacts are sorted with unguarded string field dereferences, and status enumeration ignores Is this the best way to solve the issue? Yes. The fix is at the right boundary: OpenClaw validates untrusted plugin artifact output before sorting and aligns status with the existing memory-wiki bridge flag; the mem0-side contract fix is complementary. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 3442a8e6f5da. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +31, Tests +86. Total +117 across 4 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
Review history (1 earlier review cycle)
|
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
Maintainer validation complete for Evidence:
Best-fix judgment: land the narrow host-boundary guard and status flag alignment here; retain the OpenClaw guard even after mem0 repairs its plugin because runtime plugin output can violate static SDK types. No known proof gaps or merge blockers remain. |
|
Merged via squash.
|
…yArtifacts in status (openclaw#100900) Two crashes when a memory plugin misbehaves in bridge mode: - listActiveMemoryPublicArtifacts sorted plugin-returned artifacts without validating them; an artifact missing any of the string fields the comparator dereferences (kind, workspaceDir, relativePath, absolutePath, contentType) crashed wiki status and every other bridge consumer with "Cannot read properties of undefined (reading 'localeCompare')". @mem0/openclaw-mem0 <= 1.0.14 shipped record-shaped artifacts with none of those fields, typed against a drifted SDK stub. Validate the shape, drop malformed entries (and non-array listings), and warn once naming the offending plugin -- the same treatment agentIds already got. - resolveMemoryWikiStatus gated artifact counting on vaultMode/enabled but not bridge.readMemoryArtifacts, so the wiki.status gateway method still enumerated artifacts (and hit the crash above) with the flag off, even though the sync path (bridge.ts) and CLI gateway routing honor it. The documented workaround therefore never worked for the wiki_status agent tool. Add the flag to the gate; the count reports null when imports are disabled, matching non-bridge modes.
…yArtifacts in status (openclaw#100900) Two crashes when a memory plugin misbehaves in bridge mode: - listActiveMemoryPublicArtifacts sorted plugin-returned artifacts without validating them; an artifact missing any of the string fields the comparator dereferences (kind, workspaceDir, relativePath, absolutePath, contentType) crashed wiki status and every other bridge consumer with "Cannot read properties of undefined (reading 'localeCompare')". @mem0/openclaw-mem0 <= 1.0.14 shipped record-shaped artifacts with none of those fields, typed against a drifted SDK stub. Validate the shape, drop malformed entries (and non-array listings), and warn once naming the offending plugin -- the same treatment agentIds already got. - resolveMemoryWikiStatus gated artifact counting on vaultMode/enabled but not bridge.readMemoryArtifacts, so the wiki.status gateway method still enumerated artifacts (and hit the crash above) with the flag off, even though the sync path (bridge.ts) and CLI gateway routing honor it. The documented workaround therefore never worked for the wiki_status agent tool. Add the flag to the gate; the count reports null when imports are disabled, matching non-bridge modes.
Closes #100899
What Problem This Solves
Fixes an issue where users running memory-wiki in bridge mode with a memory plugin that exports malformed public artifacts would get
Cannot read properties of undefined (reading 'localeCompare')fromwiki statusand thewiki_statusagent tool — and where settingbridge.readMemoryArtifacts: falsedid not stop the agent-tool crash, because the status path never consulted that flag.Concretely hit by
@mem0/openclaw-mem0≤ 1.0.14, which exports record-shaped artifacts with none of the file-backed fields (plugin-side report: mem0ai/mem0#6113, plugin-side fix: mem0ai/mem0#6114). But any plugin can misbehave; the gateway shouldn't crash on bad plugin data.Why This Change Was Made
Two small changes:
listActiveMemoryPublicArtifactsnow validates plugin-returned artifacts before sorting and drops malformed entries (and non-array listings) with a single warning naming the offending plugin — the same treatmentagentIdsalready received in 4644e0c. Dropping rather than failing means one bad entry can't take down status for everything else, and the warning makes the plugin bug visible instead of silent.resolveMemoryWikiStatusnow gates artifact enumeration onbridge.readMemoryArtifacts, matching the sync path inbridge.tsand the CLI's gateway routing, which already honor it. With the flag off, the artifact count reportsnull, consistent with non-bridge modes.User Impact
Bridge mode with a misbehaving memory plugin degrades to a logged warning instead of crashing
wiki status/wiki_status, andreadMemoryArtifacts: falsenow actually disables artifact enumeration on the status path.Evidence
Crash reproduced end-to-end on
ghcr.io/openclaw/openclaw:2026.6.11in Docker with@mem0/openclaw-mem01.0.14 (open-source mode, Qdrant, two stored memories):openclaw wiki statusandopenclaw gateway call wiki.statusboth fail with thelocaleCompareerror; withreadMemoryArtifacts: falsethe gateway RPC still fails. Full repro in the linked issue. Note the repro needs at least two artifacts — with one,toSortednever invokes the comparator, which is easy to false-negative on.After-fix output from this branch (same Docker rig, image built from this branch via the repo Dockerfile, stock
@mem0/openclaw-mem01.0.14, same two seeded memories). WithreadMemoryArtifacts: true, both previously-crashing commands now succeed:and the gateway log shows the new guard firing instead of the crash:
(3, not 2 — the plugin derives a third "entity" artifact from the two memories.) With
readMemoryArtifacts: false, the gateway RPC that previously crashed now returns status with the flag reflected:New regression tests use the plugin's exact malformed shape:
src/plugins/memory-state.test.ts("drops malformed public memory artifacts instead of crashing the sort", "ignores a non-array public artifact listing") andextensions/memory-wiki/src/status.test.ts("skips artifact enumeration when readMemoryArtifacts is disabled"). All three fail without the fix.Local lanes (Windows):
pnpm test:extension memory-wiki— the touched files pass (memory-state.test.ts17/17,status.test.ts10/10, both including the new tests). The lane's four failures are symlink/hardlink safety tests inbridge.test.ts/okf.test.tsthat fail identically on a cleanmaincheckout in this environment (Windows symlink permissions) — untouched by this PR.pnpm test:contracts:plugins— one failure (session-attachments.contract.test.ts), also identical on cleanmain.node scripts/check-src-extension-import-boundary.mjs --json— clean ([]). Repo lint (oxlint shards) passes.AI-assisted. I've reviewed every change and validated the behavior end-to-end myself (Docker repro above).