Problem Description
During a disaster‑recovery run, the RAG DocumentLoader used by a Hugging Face Transformers RagSequenceForGeneration pipeline crashes while ingesting documents from a cloud‑based backup. The restoration process aborts, leaving the knowledge base unavailable.
Typical error output observed in the logs:
Traceback (most recent call last):
File "/opt/app/rag_loader.py", line 112, in load_documents
documents = loader.load()
File "/usr/local/lib/python3.10/site-packages/transformers/models/rag/document_loader.py", line 254, in load
self._load_index()
File "/usr/local/lib/python3.10/site-packages/transformers/models/rag/document_loader.py", line 312, in _load_index
with open(index_path, "rb") as f:
FileNotFoundError: [Errno 2] No such file or directory: 'index.faiss'
In other instances the loader raises:
KeyError: 'doc_id_map' # missing metadata file
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x80 in position 123 # malformed JSONL
OSError: [Errno 5] Input/output error # network timeout when streaming from S3
torch.multiprocessing.ProcessError: process terminated with exit code 1 # worker crash
These failures halt the restoration of the RAG knowledge base, preventing downstream question‑answering services from starting.
Root Cause Analysis
The RAG DocumentLoader expects a specific set of artefacts to be present and correctly formatted in the backup location:
- Vector index (
index.faissorindex.pkl) – created byFAISSduring the initial indexing step. - Document metadata map (
doc_id_map.pkl) – a pickle that links FAISS IDs to original document IDs. - Raw source files (e.g.,
.jsonl,.txt) – must retain original line endings and UTF‑8 encoding. - Tokenizer and model checkpoints – saved via Hugging Face “Saving and Loading Models” API.
When a backup is restored from cloud storage (S3, Azure Blob, GCS), the following conditions commonly break these expectations:
- Missing artefacts – The backup script omitted
index.faissordoc_id_map.pkl. This matches the FileNotFoundError* and *KeyError* cases reported in real incidents (Fintech outage, Research lab GCS backup). - Corrupted or improperly encoded files – Compression or newline conversion during transfer leads to
UnicodeDecodeError. The healthcare analytics platform experienced exactly this when Azure Blob stored files with Windows line endings. - Version mismatch – The runtime environment used a different
torchversion than the one that generated the FAISS index, causingtorch.multiprocessing.ProcessErrorduring batch loading (E‑commerce failover). - Network I/O timeout – Large backups streamed directly from S3 without proper retry logic trigger
OSError: [Errno 5], as discussed in GitHub issue #12487.
In short, the DocumentLoader crashes because it cannot locate or correctly read the required index and metadata files, or because the runtime environment cannot process them.
Investigation and Debugging Steps
Follow this systematic checklist to isolate the failure mode.
- Verify backup completeness
# List objects in the backup bucket (AWS S3 example) aws s3 ls s3://rag-backup/2024-06-15/ --recursive # Expected artefacts index.faiss doc_id_map.pkl documents.jsonl tokenizer/ model/If any file is missing, the backup process must be corrected.
- Inspect file integrity
# Download a sample file and compute checksum aws s3 cp s3://rag-backup/2024-06-15/documents.jsonl ./tmp.jsonl sha256sum ./tmp.jsonl # Compare with checksum stored at backup time cat ./tmp.jsonl.sha256A mismatched checksum indicates corruption.
- Check encoding and line endings
# Detect non‑UTF8 bytes python - <<'PY' import codecs, sys with open('tmp.jsonl', 'rb') as f: data = f.read() try: data.decode('utf-8') except UnicodeDecodeError as e: print('Decode error:', e) PYIf a
UnicodeDecodeErrorappears, re‑encode the file:iconv -f utf-16 -t utf-8 tmp.jsonl -o tmp_utf8.jsonl dos2unix tmp_utf8.jsonl # normalize line endings - Validate FAISS index compatibility
# Print FAISS version used to create the index python - <<'PY' import faiss, pickle with open('index.faiss', 'rb') as f: header = f.read(8) print('FAISS index header bytes:', header) PYCross‑check with the
torchandfaissversions in the current environment:pip list | grep -E 'torch|faiss' - Run the loader in isolation with verbose logging
python -X faulthandler - <<'PY' import logging, os from transformers import RagRetriever, RagTokenizer, RagSequenceForGeneration from transformers.models.rag.document_loader import DocumentLoader logging.basicConfig(level=logging.DEBUG) loader = DocumentLoader( index_path="index.faiss", doc_id_map_path="doc_id_map.pkl", source_path="documents.jsonl", batch_size=128, num_workers=4, ) documents = loader.load() print(f'Loaded {len(documents)} documents') PYObserve the debug output for the exact point of failure.
- Check for permission or network errors
# Example of an S3 permission failure aws s3 cp s3://rag-backup/2024-06-15/index.faiss ./index.faiss # Expected error: # An error occurred (AccessDenied) when calling the GetObject operation: Access DeniedEnsure the service role has
s3:GetObjectfor the backup bucket.
Resolution
Apply the fixes that correspond to the identified root cause.
1. Restore missing artefacts
If index.faiss or doc_id_map.pkl are absent, re‑run the backup script with the --include-index flag (as documented in the official RAG guide).
# Corrected backup command (AWS example)
aws s3 sync ./rag_artifacts/ s3://rag-backup/2024-06-15/ \
--exclude "*" \
--include "index.faiss" \
--include "doc_id_map.pkl" \
--include "documents.jsonl" \
--include "tokenizer/**" \
--include "model/**"
2. Re‑encode corrupted source files
Normalize encoding and line endings before loading.
# Batch re‑encoding script
for f in *.jsonl; do
iconv -f utf-16 -t utf-8 "$f" | dos2unix > "${f}.utf8"
mv "${f}.utf8" "$f"
done
3. Align runtime dependencies
Pin torch and faiss-cpu versions to those used during indexing. Example requirements.txt:
torch==2.1.0
faiss-cpu==1.7.4
transformers==4.38.2
datasets==2.16.1
Re‑install in the recovery environment:
pip install -r requirements.txt
4. Add retry and timeout handling for cloud streams
Wrap the loader’s file opening logic with boto3 retries (or Azure SDK equivalents). Example patch:
import boto3
from botocore.config import Config
import time
s3 = boto3.client('s3', config=Config(retries={'max_attempts': 5, 'mode': 'standard'}))
def download_with_retry(bucket, key, dest):
for attempt in range(5):
try:
s3.download_file(bucket, key, dest)
return
except Exception as e:
if attempt == 4:
raise
time.sleep(2 ** attempt)
5. Verify loader configuration
Ensure the DocumentLoader is instantiated with correct paths (absolute or mounted) and matching batch_size/num_workers for the restored hardware.
# Before (incorrect relative path)
loader = DocumentLoader(
index_path="index.faiss",
doc_id_map_path="doc_id_map.pkl",
source_path="documents.jsonl",
)
# After (explicit mount point)
loader = DocumentLoader(
index_path="/mnt/backup/index.faiss",
doc_id_map_path="/mnt/backup/doc_id_map.pkl",
source_path="/mnt/backup/documents.jsonl",
batch_size=256,
num_workers=8,
)
Verification
After applying the fixes, run the loader in a controlled test run and confirm successful ingestion.
# Smoke test
python - <<'PY'
from transformers.models.rag.document_loader import DocumentLoader
loader = DocumentLoader(
index_path="/mnt/backup/index.faiss",
doc_id_map_path="/mnt/backup/doc_id_map.pkl",
source_path="/mnt/backup/documents.jsonl",
batch_size=128,
num_workers=4,
)
docs = loader.load()
print(f"✅ Loaded {len(docs)} documents")
PY
Additional validation steps:
- Check that
index.faisssize on disk matches the size recorded before the outage. - Run a quick retrieval query:
python - <<'PY' from transformers import RagRetriever, RagTokenizer, RagSequenceForGeneration tokenizer = RagTokenizer.from_pretrained("facebook/rag-token-nq") retriever = RagRetriever.from_pretrained( "facebook/rag-token-nq", index_name="custom", passages_path="/mnt/backup/documents.jsonl", index_path="/mnt/backup/index.faiss", ) model = RagSequenceForGeneration.from_pretrained("facebook/rag-token-nq", retriever=retriever) input_ids = tokenizer("What is the capital of France?", return_tensors="pt").input_ids outputs = model.generate(input_ids) print(tokenizer.batch_decode(outputs, skip_special_tokens=True)) PYIf the answer is returned without exception, the restoration succeeded.
Prevention and Best Practices
- Atomic backup snapshots: Use storage‑level snapshotting (e.g., S3 versioning, Azure Blob snapshots) to guarantee that all artefacts are captured together.
- Checksum verification: Store SHA‑256 hashes alongside each artefact and validate them during restore.
- Version pinning: Record the exact
torch,faiss, andtransformersversions in arequirements.txtfile stored with the backup. - Health‑check endpoint: Expose a lightweight endpoint that loads a single document via
DocumentLoaderand returns200 OKonly if the index and metadata are present. - Retry policies for cloud I/O: Wrap all S3/Azure/GCS interactions with exponential back‑off and idempotent retries (see GitHub issue #12487 for a reference implementation).
- Automated integration test: After each backup, run a CI job that restores the artefacts to a temporary environment and executes the smoke‑test query above.
Related Topic Hub: Model Serving Troubleshooting Hub
FAQ
- Why does the loader crash with
FileNotFoundError: index.faissonly after a restore?The backup process omitted the FAISS index file. The loader expects the index to exist locally; without it, it raises a
FileNotFoundError. Verify that the backup script includes--include-indexor equivalent. - How can I confirm which FAISS version created the index?
Inspect the first few bytes of the index file (as shown in the debugging step) and compare them with the version string printed by
faiss.__version__in the environment that performed the indexing. - Is it safe to re‑index documents instead of restoring the original index?
Re‑indexing guarantees compatibility with the current runtime but can be time‑consuming for large corpora. Use it as a fallback when the original index is corrupted or missing.
- What causes
UnicodeDecodeErroron restored JSONL files?During transfer the files were compressed or saved with a non‑UTF‑8 codec (e.g., UTF‑16) and line endings were converted to Windows style. Normalizing encoding with
iconvand runningdos2unixresolves the issue. - Can I use a different cloud provider for the backup without changing the loader code?
Yes, as long as the files are accessible via a local mount or a compatible SDK (boto3, azure-storage-blob, google-cloud-storage). The loader only requires local file paths; the download step must handle provider‑specific authentication and retries.