mastra-ai/mastra · critical

Failed to swap compacted copy into place AND failed to resto

Error message

Failed to swap compacted copy into place AND failed to restore the original — your data is intact at ${file}.old; rename it back to ${file} manually. Original error: ${err instanceof Error ? err.message : String(err)}

What it means

During the final swap, the original file is renamed to `.old` and the compacted copy is renamed into place. If the swap fails AND restoring the original back from `${file}.old` also fails, this error is thrown. It guarantees the user that their data is still intact at `${file}.old` and instructs them to rename it back manually.

Source

Thrown at mastracode/sdk/src/utils/storage-maintenance.ts:234

      throw new Error(
        `${file} was opened by another process during compaction — is another Mastra Code session running? ` +
          `Close other sessions and run /prune vacuum again.`,
      );
    }
    // Swap the compacted copy into place. The old WAL/SHM sidecars belong to
    // the old inode — they must never be paired with the new file. If any step
    // after the first rename fails, restore the original so the db path is
    // never left empty (a naive restart would otherwise create a fresh db).
    renameSync(file, `${file}.old`);
    try {
      rmSync(`${file}-wal`, { force: true });
      rmSync(`${file}-shm`, { force: true });
      renameSync(tmp, file);
    } catch (err) {
      try {
        renameSync(`${file}.old`, file);
      } catch {
        throw new Error(
          `Failed to swap compacted copy into place AND failed to restore the original — ` +
            `your data is intact at ${file}.old; rename it back to ${file} manually. ` +
            `Original error: ${err instanceof Error ? err.message : String(err)}`,
        );
      }
      rmSync(tmp, { force: true });
      throw err;
    }
    rmSync(`${file}.old`, { force: true });
    results.push({ file, bytesBefore, bytesAfter: fileSizeWithWal(file) });
  }
  return results;
}

/** `file:/path` or `file:///path` → filesystem path; undefined for non-file urls. */
function fileUrlToPath(url: string): string | undefined {
  if (!url.startsWith('file:')) return undefined;
  return url.replace(/^file:\/\//, '').replace(/^file:/, '');

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Manually restore: `mv <file>.old <file>` — the data is intact there
  2. Check volume free space and writability (`df -h`, `mount | grep ro`) before retrying, then re-run /prune vacuum
  3. On Windows/NFS, retry the vacuum from a local filesystem where renames are atomic

Example fix

// manual recovery shell
mv mastra.db.old mastra.db
rm -f mastra.db.tmp  # if a leftover compacted copy exists
Defensive patterns

Strategy: try-catch

Validate before calling

import { accessSync, constants } from 'node:fs';
// Verify the directory is writable and has space before attempting a swap
accessSync(dirname(dbFile), constants.W_OK);
const { bsize, bavail } = statfsSync(dirname(dbFile));
if (bsize * bavail < statSync(dbFile).size) throw new Error('Insufficient space/permissions for compaction swap');

Try / catch

try {
  await maintenance.results();
} catch (e) {
  if (String(e.message).includes('your data is intact at') && String(e.message).includes('.old')) {
    console.error('Recovering: renaming <db>.old back to <db>');
    renameSync(`${dbFile}.old`, dbFile);
  } else throw e;
}

Prevention

When it happens

Trigger: renameSync fails twice in a row — e.g. the volume went read-only or full, the directory permissions changed, a file watcher holds the path open on a platform where renames over open files fail (Windows), or the .old restore path is unavailable.

Common situations: Disk-full or read-only filesystem hit mid-swap; Windows antivirus/indexer locking the file during renames; NFS/network volumes with weak rename semantics; permission changes during a long vacuum.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/a93459db2f95e37f. Report an issue: GitHub.