{"record":{"id":"24fb675d4695e709","repo":"instructure/canvas-lms","slug":"unknown-keyword-s-unknown-kwargs-map-inspect-join","errorCode":null,"errorMessage":"unknown keyword(s): #{unknown_kwargs.map(&:inspect).join(\", \")}","messagePattern":"unknown keyword\\(s\\): #(.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"gems/dynamic_settings/lib/dynamic_settings/prefix_proxy.rb","lineNumber":85,"sourceCode":"    # Fetch the value at the requested key using the prefix passed to the\n    # initializer.\n    #\n    # This method is intended to retreive a single key from the keyspace and\n    # will not work for getting multiple values in a hash from the store. If\n    # you need to access values nested deeper in the keyspace use #for_prefix\n    # to move deeper in the nesting.\n    #\n    # @param key [String, Symbol] The key to fetch\n    # @param ttl [ActiveSupport::Duration] The TTL for the value in the cache,\n    #   defaults to value supplied to the constructor.\n    # @param failsafe_cache [false, PathInfo] Location on disk to store a\n    #   failsafe cached for this value, in case Consul is down on a future boot.\n    #   Should be used sparingly, since it will load a file off disk.\n    # @return [String]\n    # @return [nil] When no value was found\n    def fetch(key, ttl: @default_ttl, failsafe_cache: false, **kwargs)\n      unknown_kwargs = kwargs.keys - [:failsafe]\n      raise ArgumentError, \"unknown keyword(s): #{unknown_kwargs.map(&:inspect).join(\", \")}\" unless unknown_kwargs.empty?\n\n      # Within a given request, no reason to talk to redis/consul multiple times for the same key in the same tree\n      # The TTL is only relevant for the underlying cache-within a request we don't exceed the ttl boundary\n      DynamicSettings.request_cache.cache(CACHE_KEY_PREFIX + full_key(key)) do\n        fetch_without_request_cache(key, ttl:, failsafe_cache:, **kwargs)\n      end\n    end\n    alias_method :[], :fetch\n\n    # Extend the prefix from this instance returning a new one.\n    #\n    # @param prefix_extension [String]\n    # @param default_ttl [ActiveSupport::Duration] The default TTL to use when\n    #  fetching keys from the extended keyspace, defaults to the same value as\n    #  the receiver\n    # @return [ProxyPrefix]\n    def for_prefix(prefix_extension, default_ttl: @default_ttl)\n      self.class.new(","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/gems/dynamic_settings/lib/dynamic_settings/prefix_proxy.rb#L67-L103","documentation":"PrefixProxy#fetch accepts only `ttl`, `failsafe_cache`, and a whitelisted `failsafe` keyword. Any other keyword argument is rejected with ArgumentError before any cache or Consul lookup happens. This guards against callers passing stale or typosquatted options (e.g. from an older fetch API) down to fetch_without_request_cache.","triggerScenarios":"Calling DynamicSettings.find(...).fetch('some/key', timeout: 5) or any fetch with an unsupported keyword such as `cache:` or `default:`; also calling through a wrapper that forwards kwargs indiscriminately.","commonSituations":"Upgrading Canvas: older DynamicSettings fetch options were removed; copy-pasted code from other config loaders passing Ruby Hash#fetch-style options like `default:`; typo in a keyword name.","solutions":["Remove the unsupported keyword(s) from the fetch call; the message names them exactly","To supply a fallback, fetch and rescue nil-or-handle yourself instead of passing `default:`","Use `failsafe: true` (the only extra allowed kwarg) if you need the on-disk failsafe cache path","Check the canvas dynamic_settings docs/changelog for renamed options"],"exampleFix":"// before\nsettings.fetch('canvas/statsd/namespace', default: 'canvas')\n// after\nsettings.fetch('canvas/statsd/namespace') || 'canvas'","handlingStrategy":"validation","validationCode":"def fetch_settings(proxy, key, **opts)\n  allowed = %i[ttl failsafe_cache failsafe]\n  bad = opts.keys - allowed\n  raise ArgumentError, \"unsupported fetch opts: #{bad}\" if bad.any?\n  proxy.fetch(key, **opts)\nend","typeGuard":null,"tryCatchPattern":"begin\n  val = proxy.fetch(key)\nrescue ArgumentError => e\n  Rails.logger.warn(\"DynamicSettings fetch kwarg rejected: #{e.message}\")\n  val = nil\nend","preventionTips":["Wrap DynamicSettings access in a thin helper exposing only supported options","Grep for legacy fetch kwargs when upgrading Canvas","Use keyword-args-aware linters to catch unknown options"],"tags":["ruby","argument-error","dynamic-settings","configuration"],"backgroundTag":"invalid-argument-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"}