instructure/canvas-lms · error · UnconfiguredError
an object with an interface for loading settings must be…
Error message
an object with an interface for loading settings must be specified as 'settings_store'
What it means
CanvasSecurity decouples itself from Canvas's Setting class: consumers must inject an object exposing the settings-loading interface via CanvasSecurity.settings_store = .... Reading CanvasSecurity.settings_store when none was injected raises UnconfiguredError (unless safe_invoke: true, which returns nil).
Solutions
- Add `CanvasSecurity.settings_store = Setting` (or an equivalent object responding to the settings interface) in an initializer
- Ensure the initializer runs before any code path touching CanvasSecurity (fix boot/autoload ordering)
- Use `settings_store(safe_invoke: true)` in code that tolerates an unconfigured store
Example fix
// before CanvasSecurity::ServicesJwt.for_user(domain, user) // after # config/initializers/canvas_security.rb CanvasSecurity.settings_store = Setting CanvasSecurity::ServicesJwt.for_user(domain, user)
Defensive patterns
Strategy: validation
Validate before calling
CanvasSecurity.settings_store(safe_invoke: true) or raise 'CanvasSecurity not configured'
Type guard
def canvas_security_configured? = !CanvasSecurity.settings_store(safe_invoke: true).nil?
Try / catch
begin CanvasSecurity::ServicesJwt.for_user(domain, user) rescue CanvasSecurity::UnconfiguredError configure_canvas_security! retry end
Prevention
- Set CanvasSecurity.settings_store in an initializer
- Verify gem boot order in standalone services
- Add a smoke test asserting the store is configured
When it happens
Trigger: Invoking any CanvasSecurity API that reads settings (e.g. jwt encryption key lookups) before the host app assigned CanvasSecurity.settings_store = SomeStore.
Common situations: Using the canvas_security gem standalone or in a new service without initializer configuration; boot-order issues where CanvasSecurity is used before initializers run; test suites without the usual Canvas initializer.
Understand the failure class
Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.
Related errors
- an object with an interface for loading settings must be…
- Invalid mode: #
- Invalid URI in pv5 config: #
- Needs self.item_class to be set in #
- No region specified for: #
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/44d9f01c3e873e2a.
Report an issue: GitHub.
Appendix: source
Thrown at gems/canvas_security/lib/canvas_security.rb:53
# TODO: Maybe at one point Setting will be
# a gem on it's own or some other dependable module.
# For the moment, this is a convenient way to inject
# this base class without needing to depend on it directly.
mattr_writer :settings_store
mattr_accessor :region, :environment
# Expected interface for this object is:
# object.get(setting_name, 'default_value') # [ returning a string ]
#
# In this instance, it's expected that canvas is going to inject
# the Setting class, but we want to break depednencies that directly
# point to canvas.
def self.settings_store(safe_invoke: false)
return @@settings_store if @@settings_store
return nil if safe_invoke
raise UnconfiguredError, "an object with an interface for loading settings must be specified as 'settings_store'"
end
class AuthenticationError < RuntimeError
def response_status
401
end
end
class InvalidToken < AuthenticationError
end
class TokenExpired < AuthenticationError
end
class InvalidJwtKey < AuthenticationError
end
def self.encryption_keyView on GitHub (pinned to 1c9f0bb801)