Skip to content

Race condition in concurrent hooks corrupts mind.mv2 (Invalid sketch track magic) #3

@rafaelcalleja

Description

@rafaelcalleja

Summary

  • claude-brain runs multiple hooks in separate processes (PostToolUse, Stop, Task agents).
  • Concurrent open/write against the same .claude/mind.mv2 causes transient "Invalid sketch track magic" and "no valid commit footer".
  • Mind.open() treats "Invalid" as corruption and recreates the file, which drops frames even when backups are valid.

Environment

  • claude-brain 1.0.8
  • @memvid/sdk 2.0.146
  • Node >= 18
  • Observed on Linux (repro likely on any OS with concurrent processes)

Steps to reproduce

In repo root, run this script:

npm install
npm run build
node --input-type=module - <<'EOF'
  import { Mind } from './dist/index.js';
  import { mkdtempSync, rmSync } from 'node:fs';
  import { join } from 'node:path';
  import { tmpdir } from 'node:os';

  const dir = mkdtempSync(join(tmpdir(), 'claude-brain-race-'));
  const memoryPath = join(dir, 'mind.mv2');
  const writes = 20;

  async function writeOnce(i) {
    const mind = await Mind.open({ memoryPath, debug: false });
    await mind.remember({
      type: 'discovery',
      summary: `s${i}`,
      content: `c${i}`,
    });
  }

  Promise.allSettled(Array.from({ length: writes }, (_, i) => writeOnce(i)))
    .then((results) => {
      const failed = results.filter(r => r.status === 'rejected');
      console.log('failed', failed.length);
    })
    .finally(() => rmSync(dir, { recursive: true, force: true }));
EOF

Expected

  • All writes succeed; no backups; no "Invalid sketch track magic".

Actual

  • Frequent Invalid sketch track magic or no valid commit footer found.
  • Mind.open() recreates the file, dropping frames.

Analysis

  • This looks like a race: a reader sees an in-flight write, throws "Invalid", and the caller treats it as corruption.
  • Since hooks run in parallel processes, we need cross-process serialization around open+write.

Proposed fix

  • Use a file lock around Mind.open() and all memvid operations (open, put, read).
  • This prevents transient "Invalid" and data loss.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions