MemPalace/mempalace · error · ValueError

invalid repair backup record at line {line_number}

Error message

invalid repair backup record at line {line_number}

What it means

Raised by _iter_backup_records when a record line is valid JSON but is not a dict-bearing the required shape: the 'id' field must be a str and the 'original_document' field must be a str. Non-dict records (lists, strings, numbers) or records missing either field, or with non-string values (null, number), are rejected with the line number. This guarantees restore only replays well-formed drawer-id/document pairs.

Source

Thrown at mempalace/encoding_repair.py:430

            if not line.strip():
                continue

            try:
                record = json.loads(line)
            except json.JSONDecodeError as exc:
                raise ValueError(f"invalid backup JSON at line {line_number}") from exc

            drawer_id = record.get("id") if isinstance(record, dict) else None
            document = record.get("original_document") if isinstance(record, dict) else None

            if not isinstance(
                drawer_id,
                str,
            ) or not isinstance(
                document,
                str,
            ):
                raise ValueError(f"invalid repair backup record at line {line_number}")

            yield drawer_id, document


def repair_collection(
    collection,
    *,
    apply: bool = False,
    page_size: int = 500,
    backup_path: Optional[Union[str, Path]] = None,
    on_change: Optional[Callable[[str, str, str], None]] = None,
) -> dict:
    """Scan a collection and optionally repair high-confidence mojibake."""
    if page_size < 1:
        raise ValueError("page_size must be at least 1")

    if apply and backup_path is None:
        raise ValueError("backup_path is required when apply=True")

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Inspect the named line and check both fields: must be JSON objects with string 'id' and string 'original_document'
  2. If the backup came from another mempalace version, restore under that version or write a small migration that rewrites records to the current schema
  3. If 'original_document' is null because content was empty, rewrite it as "" — the type gate requires str
  4. Regenerate the backup via repair_collection on the current version rather than patching old files

Example fix

# migrate an old-schema backup line
# before: {"id": 42, "original_document": null}
# after:  {"id": "42", "original_document": ""}
import json
lines = open('backup.jsonl', encoding='utf-8').read().splitlines()
header, records = lines[0], lines[1:]
fixed = [json.dumps({"id": str(r["id"]), "original_document": r.get("original_document") or ""})
         for r in map(json.loads, records) if isinstance(r, dict)]
open('backup-fixed.jsonl', 'w', encoding='utf-8').write('\n'.join([header] + fixed) + '\n')
Defensive patterns

Strategy: type-guard

Validate before calling

def backup_records_well_typed(path) -> bool:
    with open(path, encoding='utf-8') as fh:
        fh.readline()
        for line in fh:
            if not line.strip():
                continue
            rec = json.loads(line)
            if not (isinstance(rec, dict) and isinstance(rec.get('id'), str)
                    and isinstance(rec.get('original_document'), str)):
                return False
    return True

Type guard

def is_valid_backup_record(rec) -> bool:
    return (isinstance(rec, dict)
            and isinstance(rec.get('id'), str)
            and isinstance(rec.get('original_document'), str))

Try / catch

try:
    restore_backup(collection, backup_path=path)
except ValueError as e:
    if "invalid repair backup record at line" in str(e):
        sys.exit(f"Record schema mismatch at the named line — migrate the backup or regenerate it")

Prevention

When it happens

Trigger: A backup record whose 'original_document' is null (drawer had empty content and the writer serialized null), an 'id' that is numeric, a record that is a bare list, or a schema drift between mempalace versions writing different field names.

Common situations: Backups from older mempalace versions with a different record schema; third-party scripts generating pseudo-backups; JSON middleware converting null handling; manual record additions.

Related errors


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