instructure/canvas-lms · error

Folder # does not exist.

Error message

Folder #{folder} does not exist.

What it means

DirectoryMailbox#connect validates the configured incoming-mail directory before processing. If folder_exists?(folder) is false — the path configured as the mailbox does not exist on disk — connect raises immediately so the mail poller fails fast instead of silently processing nothing.

Solutions

  1. Create the configured folder: mkdir -p <configured folder path>.
  2. Verify the :folder option in the incoming mail / canvas.yml settings matches an existing absolute path.
  3. In containerized deployments, confirm the mail spool volume is mounted at the configured path.
  4. Fix environment-specific config (staging vs production) so the directory exists where the process runs.

Example fix

// before (config)
incoming_mail:
  mailbox: directory
  folder: /var/mail/canvas_inbound   # does not exist
// after
# on host/container: mkdir -p /var/mail/canvas_inbound
incoming_mail:
  mailbox: directory
  folder: /var/mail/canvas_inbound   # exists and writable by app user
Defensive patterns

Strategy: validation

Validate before calling

folder = config[:folder]
raise "mailbox folder missing: #{folder}" unless File.directory?(folder)

Try / catch

begin
  mailbox.connect
rescue RuntimeError => e
  raise unless e.message =~ /Folder .* does not exist/
  FileUtils.mkdir_p(config[:folder])
  retry
end

Prevention

When it happens

Trigger: Starting IncomingMessageProcessor with a directory mailbox whose :folder option points to a non-existent path; directory removed/renamed after config was written; wrong mount point or volume not mounted when running in a container.

Common situations: Typo or wrong absolute path in incoming mail settings; Docker/Kubernetes volume not mounted; permissions or deploy changed wiping the mail spool directory; staging config pointing at a host path that doesn't exist in the new environment.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/78744f0a050bd7f2. Report an issue: GitHub.

Appendix: source

Thrown at gems/incoming_mail_processor/lib/incoming_mail_processor/directory_mailbox.rb:40

require "zlib"

require_relative "configurable_timeout"

module IncomingMailProcessor
  class DirectoryMailbox
    include ConfigurableTimeout

    attr_accessor :folder

    def initialize(options = {})
      @folder = options.fetch(:folder, "")
      @options = options
      wrap_with_timeout(self,
                        %i[folder_exists? files_in_folder read_file file? delete_file move_file create_folder])
    end

    def connect
      raise "Folder #{folder} does not exist." unless folder_exists?(folder)
    end

    def disconnect
      # nothing to do
    end

    def each_message(opts = {})
      filenames = files_in_folder(folder)
      filenames = filenames.select { |filename| Zlib.crc32(filename) % opts[:stride] == opts[:offset] } if opts[:stride] && opts[:offset]
      filenames.each do |filename|
        if file?(folder, filename)
          body = read_file(folder, filename)
          yield filename, body
        end
      end
    end

    def delete_message(filename)

View on GitHub (pinned to 1c9f0bb801)