MemPalace/mempalace · error · ValueError

could not read repair backup: {path}

Error message

could not read repair backup: {path}

What it means

Raised by _read_backup_header when opening or reading the encoding-repair backup file (JSONL with a header line) fails with an OSError. This covers the file not existing, permission denied, and unreadable-path errors. The path is included in the message, and the original OSError is chained. It fires before any parsing, distinguishing I/O problems from format problems (which get their own messages).

Source

Thrown at mempalace/encoding_repair.py:380

        {
            "format": _BACKUP_FORMAT,
            "version": _BACKUP_VERSION,
            "collection": _collection_name(collection),
        },
    )


def _read_backup_header(
    path: Path,
) -> dict:
    try:
        with path.open(
            "r",
            encoding="utf-8",
        ) as handle:
            header = json.loads(handle.readline())
    except OSError as exc:
        raise ValueError(f"could not read repair backup: {path}") from exc
    except (
        json.JSONDecodeError,
        TypeError,
    ) as exc:
        raise ValueError("repair backup has an invalid header") from exc

    if not isinstance(
        header,
        dict,
    ) or (header.get("format") != _BACKUP_FORMAT or header.get("version") != _BACKUP_VERSION):
        raise ValueError("unsupported repair backup format")

    return header


def _iter_backup_records(
    path: Path,
) -> Iterator[tuple[str, str]]:

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Check the path exists and is readable: ls -l <backup_path> and head -1 <backup_path>
  2. Use an absolute path to avoid working-directory drift
  3. Fix permissions if needed: chmod +r <backup_path> (or restore with the same user that created it)
  4. Re-run the encoding repair (repair_collection with apply) to regenerate a backup if the original is lost

Example fix

# before
restore_backup(collection, backup_path='repair-backup.jsonl')  # wrong cwd
# after
from pathlib import Path
p = Path('~/.mempalace/backups/repair-backup.jsonl').expanduser()
assert p.is_file(), f'missing backup: {p}'
restore_backup(collection, backup_path=str(p))
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def backup_readable(path) -> bool:
    p = Path(path).expanduser()
    return p.is_file() and p.stat().st_size > 0 and __import__('os').access(p, __import__('os').R_OK)

Try / catch

try:
    restore_backup(collection, backup_path=path)
except ValueError as e:
    if "could not read" in str(e):
        sys.exit(f"Backup unreadable/missing: {path} — check path and permissions")

Prevention

When it happens

Trigger: Passing a backup_path to restore_backup/repair flows that does not exist (typo, wrong directory, backup deleted after repair), lacks read permission (created under a different user/sudo), or sits on an unmounted drive.

Common situations: Running restore from a different working directory with a relative backup path; backups written by a root cron job then restored as a normal user; backup moved to external storage that is no longer mounted; shell glob for *.backup.jsonl matching nothing and passing the literal pattern.

Related errors


AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15). Data as JSON: /api/errors/b03b4ae3faa598b4. Report an issue: GitHub.