instructure/canvas-lms · warning

[I18N] localizer executed from context-less controller

Error message

[I18N] localizer executed from context-less controller

What it means

Canvas's locale inference (assign_localizer) reads request-scoped data (session locale, timezone, Accept-Language header) to pick a UI locale. When the controller has no valid request/session context (e.g. invoked outside a real HTTP request), it logs this warning and falls back to locale inference with an empty context hash instead of reading session/headers.

Solutions

  1. Ensure the controller is only invoked during a real request/render cycle with a proper request context
  2. In specs, use a controller/request spec so session and request objects exist (or stub session/request)
  3. In console or background jobs, call infer_locale with an explicit context_hash instead of the localizer
  4. If intentional, it is safe to ignore: the code proceeds with an empty context hash and infers a default locale

Example fix

// before (spec/console)
MyController.new.send(:assign_localizer)
// after
controller = MyController.new
allow(controller).to receive(:session).and_return(locale: 'en')
allow(controller).to receive(:request).and_return(ActionDispatch::TestRequest.create)
Defensive patterns

Strategy: fallback

Validate before calling

def request_context_available?
  request.present? && session.present?
end

Type guard

def has_request_context?(controller)
  controller.respond_to?(:request) && controller.request.present?
end

Try / catch

begin
  locale = controller.send(:infer_locale, context_hash)
rescue StandardError
  I18n.default_locale
end

Prevention

When it happens

Trigger: A controller (or render/service path) calls the localizer / infer_locale chain when the request/session context is nil — controllers instantiated in console, specs, or non-HTTP contexts where `session` and `request.headers` are unavailable.

Common situations: Running controller code in rails console or in specs without a request; custom controllers that bypass ApplicationController's request lifecycle; API-only controllers with no session; render calls outside the request cycle.

Understand the failure class

Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.

Related errors


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

Appendix: source

Thrown at app/controllers/application_controller.rb:1096

    request.env["extra-request-cost"] = current_cost + amount
  end

  def assign_localizer
    I18n.localizer = lambda do
      context_hash = {
        context: @context,
        user: not_fake_student_user,
        root_account: @domain_root_account
      }
      if request.present?
        # if for some reason this gets stuck
        # as global state on I18n (cleanup failure), we don't want it to
        # explode trying to access a non-existant request.
        context_hash[:session_locale] = session[:locale]
        context_hash[:session_timezone] = session[:timezone]
        context_hash[:accept_language] = request.headers["Accept-Language"]
      else
        logger.warn("[I18N] localizer executed from context-less controller")
      end
      infer_locale context_hash
    end
  end

  def set_locale
    store_session_locale
    assign_localizer
    yield if block_given?
  ensure
    # this resets any locale set in set_locale_with_localizer (implicitly called
    # on any translation call)
    I18n.locale = I18n.default_locale
    I18n.localizer = nil
  end

  def set_timezone
    store_session_timezone

View on GitHub (pinned to 1c9f0bb801)