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
- Inspect the named line: sed -n 'Np' backup.jsonl (use the number from the error) — look for truncation or stray characters
- If the tail is truncated from an interrupted run, discard the backup and regenerate it with repair_collection
- If one record was hand-edited, either restore the full original or carefully fix the JSON on that line
- 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
- Verify disk space before repairs; full disks truncate backup tails
- Do not manually trim or append lines to backups
- Archive backups compressed and read-only (chmod a-w) after creation
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
- repair backup has an invalid header
- unsupported repair backup format
- invalid repair backup record at line {line_number}
- could not read repair backup: {path}
- backup belongs to collection {backup_collection!r}, not {tar
AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15).
Data as JSON: /api/errors/a95fc77eeb82bddc.
Report an issue: GitHub.