instructure/canvas-lms · error · RuntimeError

root_account_id required

Error message

root_account_id required

What it means

Role.built_in_roles is a class-level lookup of a root account's built-in roles, keyed by root_account_id for sharded caching. Canvas raises this RuntimeError when called without a root_account_id, since the cache key and shard routing depend on it.

Solutions

  1. Pass an explicit root_account_id: Role.built_in_roles(root_account_id: account.root_account_id)
  2. Resolve the root account first (account.root_account_id || account.id) before the call
  3. Guard the call site: skip or raise a clearer error when root_account_id is blank

Example fix

// before
roles = Role.built_in_roles
// after
roles = Role.built_in_roles(root_account_id: account.root_account_id || account.id)
Defensive patterns

Strategy: validation

Validate before calling

raise ArgumentError, "root_account_id required" if root_account_id.blank?

Type guard

def has_root_account?(account) = account&.root_account_id.present? || (account&.is_a?(Account) && !account.new_record?)

Try / catch

begin
  roles = Role.built_in_roles(root_account_id: ra_id)
rescue RuntimeError => e
  raise unless e.message == "root_account_id required"
  roles = []
end

Prevention

When it happens

Trigger: Calling Role.built_in_roles without the root_account_id keyword argument, or passing nil (e.g. account&.root_account_id nil for a misconfigured/bad account record).

Common situations: Calling from code paths where the account may be a non-root account without resolving root_account first; seeds or scripts constructing roles without an account; nil propagation from an unsaved or deleted account.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at app/models/role.rb:128

  include Workflow

  workflow do
    state :active do
      event :deactivate, transitions_to: :inactive
    end
    state :inactive do
      event :activate, transitions_to: :active
    end
    state :built_in # for previously built-in roles
    state :deleted
  end

  def belongs_to_account?
    !built_in? && !deleted?
  end

  def self.built_in_roles(root_account_id:)
    raise "root_account_id required" unless root_account_id

    # giving up on in-process built-in role caching because it's probably not really worth it anymore
    RequestCache.cache("built_in_roles", root_account_id) do
      local_id, shard = Shard.local_id_for(root_account_id)
      (shard || Shard.current).activate do
        Role.where(workflow_state: "built_in", root_account_id: local_id).order(:id).to_a
      end
    end
  end

  def self.built_in_course_roles(root_account_id:)
    built_in_roles(root_account_id:).select(&:course_role?)
  end

  def self.visible_built_in_roles(root_account_id:)
    built_in_roles(root_account_id:).select(&:visible?)
  end

View on GitHub (pinned to 1c9f0bb801)