Skip to content

saveGraph() in src/memory uses non-atomic fs.writeFile — risk of corrupted memory file on interruption #4614

Description

@Selven81

KnowledgeGraphManager.saveGraph() (src/memory/index.ts) writes the entire
knowledge graph directly to the memory file with:

await fs.writeFile(this.memoryFilePath, lines.join("\n"));

fs.writeFile truncates the target file and writes the new content in place.
If the process is interrupted mid-write (SIGKILL, container/host stop, crash,
OOM kill, power loss, etc.), the memory file is left truncated or partially
written — there is no atomicity guarantee.

Since this file is the sole persistence layer for the knowledge graph, a
corrupted write means silent, permanent loss of accumulated memory, with no
recovery path other than an external backup.

How to reproduce / how I found it

I verified the behavior by reading the installed source directly
(@modelcontextprotocol/server-memory, local version, same logic in
saveGraph). A realistic scenario that surfaced it: a backup script that
stops a Distrobox/Podman container hosting the server process (SIGTERM
followed by distrobox stop) — if the server is writing to the file at that
moment, the file risks being left corrupted.

Suggested fix

Write to a temporary file first, then use fs.rename(), which is atomic on
POSIX filesystems (either the old file stays intact, or the new one is
complete — never an intermediate state):

private async saveGraph(graph: KnowledgeGraph): Promise<void> {
  const lines = [...]; // unchanged
  const tmpPath = this.memoryFilePath + '.tmp';
  await fs.writeFile(tmpPath, lines.join("\n"));
  await fs.rename(tmpPath, this.memoryFilePath);
}

I applied and verified this change locally with success (no leftover .tmp
file after rename, subsequent reads/writes worked normally).

Environment

  • @modelcontextprotocol/server-memory (locally installed via npm)
  • Node.js on Linux (Bazzite/Distrobox)
  • Bug also present in the current GitHub version (main, v0.6.3, index.ts)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions