instructure/canvas-lms · warning
Unable to read setting: #
Error message
Unable to read setting: #{e} What it means
Setting.get reads values from the settings table, but during early boot (rake tasks, initializers, db:create) the database or settings table may not exist yet. Canvas rescues ActiveRecord::StatementInvalid / ConnectionNotEstablished, logs 'Unable to read setting: ...', and falls back to the provided default. It is a graceful-degradation warning, not a fatal failure.
Solutions
- Run `bundle exec rake db:migrate` so the settings table exists before code that reads Settings
- Ensure DATABASE_URL/database.yml is correct and the database server is reachable
- Defer Setting.get calls out of boot/initializers until after DB initialization, or pass an explicit default
- If it only appears during asset precompile or db:create, it is expected noise — the default is used
Example fix
# before (initializer runs before DB exists)
TIMEOUT = Setting.get('request_timeout', 30).to_i
# after: defer reading until first use
def self.request_timeout
@request_timeout ||= Setting.get('request_timeout', 30).to_i
end Defensive patterns
Strategy: fallback
Validate before calling
begin
ActiveRecord::Base.connection.execute('SELECT 1 FROM settings LIMIT 1')
rescue ActiveRecord::StatementInvalid, ActiveRecord::ConnectionNotEstablished
# DB not ready; use default
end Type guard
def settings_available?
ActiveRecord::Base.connected? &&
ActiveRecord::Base.connection.table_exists?(:settings)
rescue ActiveRecord::ConnectionNotEstablished
false
end Try / catch
begin
value = Setting.get('my_setting', nil)
rescue ActiveRecord::StatementInvalid, ActiveRecord::ConnectionNotEstablished
value = DEFAULT_MY_SETTING
end Prevention
- Always pass an explicit default to Setting.get
- Run db:migrate before booting processes that read Settings
- Avoid Setting.get in initializers; read lazily at first use
- Ensure DATABASE_URL/database.yml is valid in build/CI environments
When it happens
Trigger: Calling Setting.get (often indirectly from initializers, feature flags, or config loading) before migrations have run, when the settings table doesn't exist, or when no database connection is established (e.g. during assets:precompile or db setup tasks).
Common situations: Fresh Canvas checkout without db:migrate; running yarn/webpack builds that boot Rails without a configured DATABASE_URL; CI steps that load the environment before creating the database;短暂 DB outage during boot.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- assessor and assessee required
- association required
- can only forward one conversation at a time
- can't accept
- Can't update submission scores unless it's completed
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/a89e09c92c31f8ea.
Report an issue: GitHub.
Appendix: source
Thrown at app/models/setting.rb:48
elsif expires_in
# ignore the in-proc cache, but check redis; it will have been properly
# cleared by whoever set it, they just have no way to clear the in-proc cache
@all_settings = MultiCache.fetch("all_settings", &fetch)
else
# use both caches
@all_settings ||= MultiCache.fetch("all_settings", &fetch)
end
if all_settings.key?(name)
all_settings[name]&.to_s
else
Setting.set(name, default) if set_if_nx
default&.to_s
end
end
rescue ActiveRecord::StatementInvalid, ActiveRecord::ConnectionNotEstablished => e
# the db may not exist yet
Rails.logger&.warn("Unable to read setting: #{e}")
default&.to_s
end
# Note that after calling this, you should send SIGHUP to all running Canvas processes
def self.set(name, value, secret: nil)
s = Setting.where(name:).first_or_initialize
s.value = value&.to_s
s.secret = secret unless secret.nil?
s.save!
cache.delete(name)
@all_settings = nil
MultiCache.delete("all_settings")
if defined?(Rails::Console)
message = Setting.get("setting_set_sighup_required_message", "** NOTE: After calling `Setting.set`, SIGHUP must be sent to all Canvas processes **")
Rails.logger.info(message)
end
endView on GitHub (pinned to 1c9f0bb801)