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"

        # BCC

View on GitHub (pinned to e318778c9b)

Solutions

  1. Obtain a decrypted copy of the .msg file before conversion
  2. Skip the encrypted file and log/flag it in your pipeline (catch ValueError around run)
  3. 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

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


AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30). Data as JSON: /api/errors/f9218d764ac24302. Report an issue: GitHub.