deepset-ai/haystack · error
The MSG file is encrypted and cannot be read.
Error message
The MSG file is encrypted and cannot be read.
What it means
MSGToDocument._convert detects whether the loaded MSG (Outlook .msg) file is encrypted via _is_encrypted(msg); encrypted MSG files cannot be parsed by the extract-msg backend, so the component raises ValueError to signal the file is unreadable rather than returning garbage.
Source
Thrown at haystack/components/converters/msg.py:91
"""
recip_str = ""
if recip.name != "":
recip_str += f"{recip.name} "
if recip.email_address != "":
recip_str += f"{recip.email_address}"
return recip_str
def _convert(self, file_content: io.BytesIO) -> tuple[str, list[ByteStream]]:
"""
Converts the MSG file content into text and extracts any attachments.
:param file_content: The MSG file content as a binary stream.
:returns: A tuple containing the extracted email text and a list of ByteStream objects for attachments.
:raises ValueError: If the MSG file is encrypted and cannot be read.
"""
msg = Message.load(file_content)
if self._is_encrypted(msg):
raise ValueError("The MSG file is encrypted and cannot be read.")
txt = ""
# Sender
if msg.sender is not None:
txt += f"From: {msg.sender}\n"
# To
recipients_str = ",".join(self._create_recipient_str(r) for r in msg.recipients)
if recipients_str != "":
txt += f"To: {recipients_str}\n"
# CC
cc_header = msg.message_headers.get("Cc") or msg.message_headers.get("CC")
if cc_header is not None:
txt += f"Cc: {cc_header}\n"
# BCCView on GitHub (pinned to e318778c9b)
Solutions
- Obtain a decrypted copy of the .msg file before conversion
- Skip the encrypted file and log/flag it in your pipeline (catch ValueError around run)
- Ask the sender to resend the email without encryption/DRM protection
Example fix
// before
text, attachments = converter.run(sources=[encrypted_stream])
// after
try:
text, attachments = converter.run(sources=[stream])
except ValueError:
skipped.append(stream) # handle encrypted file separately Defensive patterns
Strategy: try-catch
Try / catch
try:
text, attachments = msg_converter.run(sources=[stream])
except ValueError as e:
if "encrypted" in str(e):
log.warning("Skipping encrypted MSG: %s", stream.meta.get("file_name"))
else:
raise Prevention
- Pre-scan .msg corpora for encryption flags before batch conversion
- Request unencrypted/DRM-free copies for ingestion pipelines
- Isolate per-file conversion in try/except so one encrypted file doesn't halt a batch
When it happens
Trigger: Calling MSGToDocument.run() on a ByteStream whose content is an encrypted/DRM-protected Outlook .msg file; Message.load succeeds structurally but _is_encrypted returns True.
Common situations: Processing corporate mailboxes with Information Rights Management (IRM/DRM) protected emails; batch-converting archived .msg files where some are S/MIME encrypted.
Related errors
- Document with ID '{doc.id}' comes from the PDF file '{resolv
- No `jq_schema` nor `content_key` specified. Set either or bo
- Invalid Jinja template '{template}': {e}
- No input data provided for output adaptation
- Undefined variable in the template {self.template}; kwargs:
AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30).
Data as JSON: /api/errors/f9218d764ac24302.
Report an issue: GitHub.