instructure/canvas-lms · error
Unrecognized Content-Type: #
Error message
Unrecognized Content-Type: #{incoming_message.mime_type.inspect} What it means
IncomingMessageProcessor#extract_body only understands text/plain, text/html, or a nil MIME type on incoming messages. Any other Content-Type (e.g. multipart variants, images, or exotic types surfacing from misparsed mail) has no extraction path and raises so the message can be handled by error processing instead of producing an empty body.
Solutions
- Inspect the offending message's Content-Type header to confirm why it isn't text/plain or text/html.
- Ensure the mail library (Mail gem) fully parses multipart messages so extract_body receives a leaf part, not the multipart container.
- Fix malformed MIME boundaries upstream or reject/skip such messages in process_single error handling.
- If a new legitimate type must be supported, extend the case statement to map it (e.g. decode HTML branch for multipart/related leaf parts).
Example fix
// before # raise "Unrecognized Content-Type: multipart/related" // after (in code that feeds extract_body) parts = incoming_message.multipart? ? incoming_message.text_part : incoming_message raise ArgumentError, 'no text part' if parts.nil? extract_body(parts)
Defensive patterns
Strategy: try-catch
Validate before calling
mime = incoming_message.mime_type return :unsupported unless mime.nil? || %w[text/plain text/html].include?(mime)
Type guard
def supported_mime?(msg) msg.mime_type.nil? || %w[text/plain text/html].include?(msg.mime_type) end
Try / catch
begin
processor.process_single(message)
rescue RuntimeError => e
raise unless e.message.start_with?('Unrecognized Content-Type:')
mailbox.move_file(message.id, :failure) # route to failure folder for inspection
end Prevention
- Let the Mail gem fully decompose multipart messages before extracting bodies.
- Quarantine non-text messages to a failure folder instead of crashing the poll loop.
- Log the Content-Type of rejected messages to spot recurring client patterns.
When it happens
Trigger: Processing an inbound email whose top-level MIME type is neither text/plain nor text/html — commonly multipart/* that the mail library did not decompose, or messages with attachments as the primary part, messages with content types like application/* forwarded whole.
Common situations: Non-English mail clients emitting odd content types; emails where the parser fails to split multipart (malformed MIME boundaries); forwarded message/rfc822 bodies; HTML-only newsletters parsed as multipart/related without a text part handled upstream.
Related errors
- AI response appears truncated - the response may have…
- Folder # does not exist.
- Invalid JSON response: could not extract valid JSON array
- unrecognized setting sent to IncomingMessageProcessor: #
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/c6820aeab287824a.
Report an issue: GitHub.
Appendix: source
Thrown at gems/incoming_mail_processor/lib/incoming_mail_processor/incoming_message_processor.rb:265
end
private
def extract_body(incoming_message)
if incoming_message.multipart?
html_part = incoming_message.html_part
text_part = incoming_message.text_part
html_body = self.class.utf8ify(html_part.body.decoded, html_part.charset) if html_part
text_body = self.class.utf8ify(text_part.body.decoded, text_part.charset) if text_part
else
case incoming_message.mime_type
when "text/plain", nil
text_body = self.class.utf8ify(incoming_message.body.decoded, incoming_message.charset)
when "text/html"
html_body = self.class.utf8ify(incoming_message.body.decoded, incoming_message.charset)
else
raise "Unrecognized Content-Type: #{incoming_message.mime_type.inspect}"
end
end
if html_body && !text_body
text_body = self.class.html_to_text(html_body)
end
if text_body && !html_body
html_body = self.class.format_message(text_body).first
end
[text_body, html_body]
end
def report_stats(incoming_message, mailbox_account)
InstStatsd::Statsd.distributed_increment("incoming_mail_processor.incoming_message_processed.#{mailbox_account.escaped_address}",
short_stat: "incoming_mail_processor.incoming_message_processed",
tags: { mailbox: mailbox_account.escaped_address })View on GitHub (pinned to 1c9f0bb801)