MemPalace/mempalace · error · ValueError

invalid backup JSON at line {line_number}

Error message

invalid backup JSON at line {line_number}

What it means

Raised by _iter_backup_records while streaming backup records (lines 2+, since line 1 is the header) when a non-empty line fails json.loads with JSONDecodeError. The message includes the 1-based line number so the exact corrupt record can be found. Like the header checks, this is a fail-fast gate: restore validates the complete file before the first write, so one bad line aborts everything rather than half-applying a restore.

Source

Thrown at mempalace/encoding_repair.py:418

    with path.open(
        "r",
        encoding="utf-8",
    ) as handle:
        # Skip the validated header.
        handle.readline()

        for line_number, line in enumerate(
            handle,
            start=2,
        ):
            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,

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Inspect the named line: sed -n 'Np' backup.jsonl (use the number from the error) — look for truncation or stray characters
  2. If the tail is truncated from an interrupted run, discard the backup and regenerate it with repair_collection
  3. If one record was hand-edited, either restore the full original or carefully fix the JSON on that line
  4. Validate the whole file: python -c "[json.loads(l) for l in open('backup.jsonl') if l.strip()]"

Example fix

# before: manual deletion broke a line
# line 42: {"id": "drawer-41", "original_document": "half of a docu
# after: regenerate instead of editing backups
result = repair_collection(collection, apply=False)
restore_backup(collection, backup_path=result['backup_path'])
Defensive patterns

Strategy: validation

Validate before calling

def backup_records_all_parse(path) -> bool:
    try:
        with open(path, encoding='utf-8') as fh:
            fh.readline()
            return all(json.loads(l) is not None for l in fh if l.strip())
    except (json.JSONDecodeError, OSError):
        return False

Try / catch

try:
    restore_backup(collection, backup_path=path)
except ValueError as e:
    if "invalid backup JSON at line" in str(e):
        line_no = int(str(e).rsplit('line', 1)[1])
        sys.exit(f"Corrupt record at line {line_no}; regenerate the backup")

Prevention

When it happens

Trigger: A backup with a truncated tail (process killed or disk full during backup write), a hand-edited middle line with a syntax error, or CRLF/encoding artifacts inside one record. Any single malformed line among thousands triggers this.

Common situations: Interrupted repair runs; backups edited to remove a record by deleting half a line; log-rotation tools truncating files; files transferred through a channel that mangled multi-byte characters.

Related errors


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