{"record":{"id":"c94bdc35309ef6cc","repo":"instructure/canvas-lms","slug":"an-object-with-an-interface-for-loading-settings-must-be","errorCode":null,"errorMessage":"an object with an interface for loading settings must be specified as 'settings_store'","messagePattern":"an object with an interface for loading settings must be specified as 'settings_store'","errorType":"exception","errorClass":"UnconfiguredError","httpStatus":null,"severity":"error","filePath":"gems/canvas_cache/lib/canvas_cache.rb","lineNumber":50,"sourceCode":"  class << self\n    # TODO: Maybe at one point Setting will be\n    # a gem on it's own or some other dependable module.\n    # For the moment, this is a convenient way to inject\n    # this base class without needing to depend on it directly.\n    # This is safe to change after initialization, since none of the\n    # returned settings are persistently cached in memory\n    attr_writer :settings_store\n\n    # Expected interface for this object is:\n    #   object.get(setting_name, 'default_value') # [ returning a string ]\n    #\n    # In this instance, it's expected that canvas is going to inject\n    # the Setting class, but we want to break depednencies that directly\n    # point to canvas.\n    def settings_store\n      return @settings_store if @settings_store\n\n      raise UnconfiguredError, \"an object with an interface for loading settings must be specified as 'settings_store'\"\n    end\n  end\n\n  @settings_store = MemorySettings.new\nend\n","sourceCodeStart":32,"sourceCodeEnd":56,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/gems/canvas_cache/lib/canvas_cache.rb#L32-L56","documentation":"CanvasCache::Redis.settings_store lazily returns the injected settings object (something responding to Setting's interface, e.g. canvas's Setting class); at gem load it defaults to MemorySettings. If the module was re-initialized or reset and no store was injected, it raises UnconfiguredError. The gem deliberately avoids depending on canvas directly, so the app must supply its Setting-like store.","triggerScenarios":"Accessing CanvasCache::Redis.settings_store (directly or via code reading Redis settings) before the host app has called CanvasCache::Redis.settings_store = Setting in an environment where the default MemorySettings initializer didn't run or was reset.","commonSituations":"Using canvas_cache outside a full Canvas app (gem tests, another service) without configuring the store; upgrading canvas_cache and the injection line being dropped; code referencing the store during boot before initializers run.","solutions":["In app initialization, set CanvasCache::Redis.settings_store = Setting (or a compatible object)","Keep the gem's own default (MemorySettings) by not resetting the module state; rely on @settings_store initialized at load","If boot-order is the issue, wrap consumers so they only touch settings_store after initializers complete","For gem-only usage, inject MemorySettings (or a stub) explicitly"],"exampleFix":"// before\n# nothing set in initializer\n// after\n# config/initializers/canvas_cache.rb\nCanvasCache::Redis.settings_store = Setting","handlingStrategy":"validation","validationCode":"CanvasCache::Redis.settings_store = Setting unless CanvasCache::Redis.instance_variable_get(:@settings_store)","typeGuard":"def settings_configured?\n  CanvasCache::Redis.instance_variable_get(:@settings_store).present?\nend","tryCatchPattern":"begin\n  store = CanvasCache::Redis.settings_store\nrescue CanvasCache::UnconfiguredError => e\n  Rails.logger.fatal(\"canvas_cache unconfigured: #{e.message}\")\n  CanvasCache::Redis.settings_store = MemorySettings.new\nend","preventionTips":["Configure settings_store in a boot initializer","Never reset CanvasCache::Redis module state after boot","Add a health check asserting the store is injected"],"tags":["ruby","redis","configuration"],"backgroundTag":"missing-required-config","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}