Skip to content

fix(memory-wiki): bridge status crashes on malformed memory-plugin artifacts and ignores readMemoryArtifacts=false#100900

Merged
vincentkoc merged 1 commit into
openclaw:mainfrom
huveewomg:fix/memory-wiki-bridge-artifact-crashes
Jul 6, 2026
Merged

fix(memory-wiki): bridge status crashes on malformed memory-plugin artifacts and ignores readMemoryArtifacts=false#100900
vincentkoc merged 1 commit into
openclaw:mainfrom
huveewomg:fix/memory-wiki-bridge-artifact-crashes

Conversation

@huveewomg

@huveewomg huveewomg commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

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') from wiki status and the wiki_status agent tool — and where setting bridge.readMemoryArtifacts: false did 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:

  • listActiveMemoryPublicArtifacts now validates plugin-returned artifacts before sorting and drops malformed entries (and non-array listings) with a single warning naming the offending plugin — the same treatment agentIds already 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.
  • resolveMemoryWikiStatus now gates artifact enumeration on bridge.readMemoryArtifacts, matching the sync path in bridge.ts and the CLI's gateway routing, which already honor it. With the flag off, the artifact count reports null, 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, and readMemoryArtifacts: false now actually disables artifact enumeration on the status path.

Evidence

  • Crash reproduced end-to-end on ghcr.io/openclaw/openclaw:2026.6.11 in Docker with @mem0/openclaw-mem0 1.0.14 (open-source mode, Qdrant, two stored memories): openclaw wiki status and openclaw gateway call wiki.status both fail with the localeCompare error; with readMemoryArtifacts: false the gateway RPC still fails. Full repro in the linked issue. Note the repro needs at least two artifacts — with one, toSorted never 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-mem0 1.0.14, same two seeded memories). With readMemoryArtifacts: true, both previously-crashing commands now succeed:

    $ openclaw wiki status
    Wiki vault mode: bridge  Vault: ready (/home/node/.openclaw/wiki/main)  Render mode: native
    Bridge: enabled (0 exported artifacts)  ...
    Warnings: - Bridge mode is enabled but the active memory plugin is not exporting any public memory artifacts yet.
    
    $ openclaw gateway call wiki.status
    Gateway call: wiki.status
    { "vaultMode": "bridge", ..., "bridge": { "enabled": true, "readMemoryArtifacts": true, ... }, ... }
    

    and the gateway log shows the new guard firing instead of the crash:

    [plugins/memory-state] ignoring 3 malformed public memory artifact(s) from plugin "openclaw-mem0":
    artifacts must include string kind, workspaceDir, relativePath, absolutePath, and contentType
    

    (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:

    $ openclaw gateway call wiki.status
    Gateway call: wiki.status
    { "vaultMode": "bridge", ..., "bridge": { "enabled": true, "readMemoryArtifacts": false, ... }, ... }
    
  • 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") and extensions/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.ts 17/17, status.test.ts 10/10, both including the new tests). The lane's four failures are symlink/hardlink safety tests in bridge.test.ts/okf.test.ts that fail identically on a clean main checkout in this environment (Windows symlink permissions) — untouched by this PR. pnpm test:contracts:plugins — one failure (session-attachments.contract.test.ts), also identical on clean main. 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).

…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.
@clawsweeper

clawsweeper Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 6, 2026, 10:22 AM ET / 14:22 UTC.

Summary
The PR filters malformed memory plugin public artifacts before sorting and makes memory-wiki status skip artifact enumeration when bridge.readMemoryArtifacts is false, with regression tests.

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 readMemoryArtifacts=false; the linked issue also gives a Docker repro on v2026.6.11.

Review metrics: 1 noteworthy metric.

  • Config behavior aligned: 1 existing bridge flag applied to 1 additional status path. The change makes readMemoryArtifacts=false consistently disable artifact enumeration without adding a new config surface.

Stored data model
Persistent data-model change detected: unknown-data-model-change: src/plugins/memory-state.ts, vector/embedding metadata: extensions/memory-wiki/src/status.test.ts, vector/embedding metadata: src/plugins/memory-state.test.ts, vector/embedding metadata: src/plugins/memory-state.ts. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #100899
Summary: This PR is the candidate fix for the canonical memory-wiki bridge status crash issue; adjacent prior artifact-hardening work is related but already closed and does not supersede this PR.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦞 diamond lobster
Proof: 🦞 diamond lobster
Patch quality: 🦞 diamond lobster
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Next step before merge

  • [P2] No repair job is needed; with proof sufficient and no review findings, the remaining action is normal maintainer merge review.

Security
Cleared: The diff only hardens plugin data validation and status gating plus tests; it does not change dependencies, workflows, secrets, package metadata, or code-execution surfaces.

Review details

Best 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 readMemoryArtifacts=false; the linked issue also gives a Docker repro on v2026.6.11.

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 changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The updated PR body includes after-fix Docker CLI/Gateway output and the warning log for both readMemoryArtifacts=true and false, showing the changed behavior in a real setup.
  • add rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The updated PR body includes after-fix Docker CLI/Gateway output and the warning log for both readMemoryArtifacts=true and false, showing the changed behavior in a real setup.
  • remove rating: 🦪 silver shellfish: Current PR rating is rating: 🦞 diamond lobster, so this older rating label is no longer current.
  • remove status: 📣 needs proof: Current PR status label is status: 👀 ready for maintainer look.

Label justifications:

  • P1: The PR fixes a shipped memory-wiki bridge crash that blocks wiki status and the wiki_status agent tool for affected memory-plugin users.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The updated PR body includes after-fix Docker CLI/Gateway output and the warning log for both readMemoryArtifacts=true and false, showing the changed behavior in a real setup.
  • proof: sufficient: Contributor real behavior proof is sufficient. The updated PR body includes after-fix Docker CLI/Gateway output and the warning log for both readMemoryArtifacts=true and false, showing the changed behavior in a real setup.
Evidence reviewed

PR surface:

Source +31, Tests +86. Total +117 across 4 files.

View PR surface stats
Area Files Added Removed Net
Source 2 33 2 +31
Tests 2 86 0 +86
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 4 119 2 +117

What I checked:

  • Current main crash path: Current main calls the active memory plugin artifact provider and sorts returned artifacts with unguarded localeCompare calls on file-backed fields, so record-shaped plugin artifacts can crash status enumeration. (src/plugins/memory-state.ts:323, 3442a8e6f5da)
  • Current main status gate: Current main counts bridge public artifacts when appConfig, bridge mode, and bridge.enabled are present, but it does not check config.bridge.readMemoryArtifacts. (extensions/memory-wiki/src/status.ts:213, 3442a8e6f5da)
  • Sibling paths honor the flag: The bridge sync path and CLI gateway-routing helper already check bridge.readMemoryArtifacts, supporting the PR's choice to align status with the existing flag contract. (extensions/memory-wiki/src/bridge.ts:223, 3442a8e6f5da)
  • Docs contract: The memory-wiki docs say status, doctor, and bridge import route through Gateway only when bridge mode and artifact reads are enabled; otherwise they keep local/offline behavior. Public docs: docs/plugins/memory-wiki.md. (docs/plugins/memory-wiki.md:51, 3442a8e6f5da)
  • PR diff hardens the boundary: The PR adds validation for the string fields used by the sorter, ignores non-array listings, warns on malformed plugin data, and adds the existing readMemoryArtifacts flag to the status enumeration gate. (src/plugins/memory-state.ts:323, f452b779a598)
  • Regression coverage: The PR adds tests for record-shaped malformed artifacts, non-array artifact listings, and no status enumeration when readMemoryArtifacts is disabled. (src/plugins/memory-state.test.ts:237, f452b779a598)

Likely related people:

  • vincentkoc: File history shows this account introduced and expanded the memory-wiki bridge/status surfaces, and the live PR is assigned to this account. (role: feature owner and recent assignee; confidence: high; commits: 5716d83336fd, 947a43dae311, 5a6d80da7f23; files: extensions/memory-wiki/src/status.ts, extensions/memory-wiki/src/bridge.ts, extensions/memory-wiki/src/cli.ts)
  • yu-xin-c: This account authored the prior merged fix that normalized public memory artifacts missing agentIds, directly adjacent to this PR's malformed-artifact guard. (role: adjacent boundary-hardening contributor; confidence: high; commits: 4644e0c10256; files: src/plugins/memory-state.ts, src/plugins/memory-state.test.ts)
  • steipete: Recent history shows this account repeatedly refactored memory plugin state and memory-wiki bridge/storage paths around the same runtime boundary. (role: memory plugin state and memory-wiki contributor; confidence: medium; commits: 0cf51b77fb69, a4236bd6faf6, 3430a2d26f52; files: src/plugins/memory-state.ts, extensions/memory-wiki/src/bridge.ts, extensions/memory-wiki/src/cli.ts)
  • SunnyShu0925: This account recently repaired malformed vault-scan handling in the same memory-wiki status module, making them a useful adjacent reviewer for status-path behavior. (role: recent status-path contributor; confidence: medium; commits: 1289abddcb96; files: extensions/memory-wiki/src/status.ts, extensions/memory-wiki/src/status.test.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (1 earlier review cycle)
  • reviewed 2026-07-06T13:44:28.733Z sha f452b77 :: needs real behavior proof before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. labels Jul 6, 2026
@vincentkoc vincentkoc self-assigned this Jul 6, 2026
@huveewomg

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 6, 2026
@vincentkoc

Copy link
Copy Markdown
Member

Maintainer validation complete for f452b779a598224e098d770f2317c3eec7f51555.

Evidence:

  • Confirmed the shipped failure path against ghcr.io/openclaw/openclaw:2026.6.11 evidence and current source: malformed plugin artifacts reach unguarded string sorting, while the status path omitted the existing readMemoryArtifacts gate.
  • Inspected @mem0/openclaw-mem0 1.0.14 source directly: its provider returns record-shaped { id, type, title, content, ... } values rather than OpenClaw's file-backed artifact contract. The complementary upstream repair is fix(openclaw): stop registering malformed artifacts and partial search manager mem0ai/mem0#6114.
  • node scripts/run-vitest.mjs src/plugins/memory-state.test.ts extensions/memory-wiki/src/status.test.ts extensions/memory-wiki/src/bridge.test.ts passed: 39 tests.
  • git diff --check passed.
  • Fresh gpt-5.5 high-reasoning autoreview passed with no accepted/actionable findings.
  • Native scripts/pr prepare-run 100900 passed at the exact PR head using hosted exact-head gates; full CI, QA Smoke CI, plugin contracts, lint, production types, and the memory runtime quality lane are green.

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.

@vincentkoc
vincentkoc merged commit ddddb3d into openclaw:main Jul 6, 2026
164 of 179 checks passed
@vincentkoc

Copy link
Copy Markdown
Member

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 7, 2026
…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.
giodl73-repo pushed a commit to giodl73-repo/openclaw that referenced this pull request Jul 8, 2026
…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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

extensions: memory-wiki P1 High-priority user-facing bug, regression, or broken workflow. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: memory-wiki bridge status crashes with localeCompare on malformed memory-plugin artifacts; readMemoryArtifacts=false doesn't prevent it

2 participants