{"record":{"id":"681a23ee550ebfc4","repo":"instructure/canvas-lms","slug":"invalid-options-invalid-keys-inspect-must-be-in-valid-keys","errorCode":null,"errorMessage":"invalid options - #{invalid_keys.inspect} (must be in #{valid_keys.inspect})","messagePattern":"invalid options - #(.+?) \\(must be in #(.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/models/course.rb","lineNumber":4061,"sourceCode":"  def allow_wiki_comments\n    self[\"allow_wiki_comments\"]\n  end\n\n  delegate :name, to: :account, prefix: true\n\n  def term_name\n    enrollment_term.name\n  end\n\n  cattr_accessor :settings_options\n  self.settings_options = {}\n\n  def self.add_setting(setting, opts = {})\n    setting = setting.to_sym\n    settings_options[setting] = opts\n    valid_keys = %i[boolean default inherited alias arbitrary]\n    invalid_keys = opts.except(*valid_keys).keys\n    raise \"invalid options - #{invalid_keys.inspect} (must be in #{valid_keys.inspect})\" if invalid_keys.any?\n\n    cast_expression = \"val.to_s.presence\"\n    cast_expression = \"val\" if opts[:arbitrary]\n    if opts[:boolean]\n      opts[:default] ||= false\n      cast_expression = \"Canvas::Plugin.value_to_boolean(val)\"\n    end\n    class_eval <<~RUBY, __FILE__, __LINE__ + 1\n      def #{setting}\n        if Course.settings_options[#{setting.inspect}][:inherited]\n          inherited = RequestCache.cache('inherited_course_setting', #{setting.inspect}, self.global_account_id) do\n            self.account.send(#{setting.inspect})\n          end\n          if inherited[:locked] || settings_frd[#{setting.inspect}].nil?\n            inherited[:value]\n          else\n            settings_frd[#{setting.inspect}]\n          end","sourceCodeStart":4043,"sourceCodeEnd":4079,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/course.rb#L4043-L4079","documentation":"Course.add_setting validates that the opts hash passed when registering a course setting contains only whitelisted keys (:boolean, :default, :inherited, :alias, :arbitrary). Any unknown option key raises this error at registration time, and the invalid/valid key lists are included in the message.","triggerScenarios":"Calling Course.add_setting(:my_setting, typoed_opt: true) or passing a non-supported key like Course.add_setting(:x, {type: :boolean}) during plugin/initializer load.","commonSituations":"Typo in option names in an initializer or plugin registration; copying options from another add_setting-like API; a Canvas version changed the allowed key set so old registration code now fails.","solutions":["Remove or rename the offending keys listed in invalid_keys to ones in valid_keys (boolean, default, inherited, alias, arbitrary).","If you need a free-form string value, pass arbitrary: true and drop any custom type options.","Check the Canvas version's Course.add_setting whitelist; upgrade guides may list renamed options."],"exampleFix":"// before\nCourse.add_setting(:homeroom_course, {type: :boolean, default: false})\n\n// after\nCourse.add_setting(:homeroom_course, {boolean: true, default: false})","handlingStrategy":"validation","validationCode":"VALID = %i[boolean default inherited alias arbitrary]\nbad = opts.except(*VALID).keys\nraise ArgumentError, \"bad opts #{bad}\" if bad.any?","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Copy option keys only from existing add_setting calls","Add an initializer-load test registering all custom settings","Watch Canvas release notes for whitelist changes"],"tags":["ruby-on-rails","configuration","validation"],"backgroundTag":"invalid-config-value","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"}