{"record":{"id":"5bf549395d4b6085","repo":"ruby-concurrency/concurrent-ruby","slug":"key-not-found","errorCode":null,"errorMessage":"key not found","messagePattern":"key not found","errorType":"exception","errorClass":"KeyError","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby/concurrent/map.rb","lineNumber":328,"sourceCode":"    end\n\n    # @!visibility private\n    def marshal_load(hash)\n      initialize\n      populate_from(hash)\n    end\n\n    undef :freeze\n\n    # @!visibility private\n    def inspect\n      format '%s entries=%d default_proc=%s>', to_s[0..-2], size.to_s, @default_proc.inspect\n    end\n\n    private\n\n    def raise_fetch_no_key\n      raise KeyError, 'key not found'\n    end\n\n    def initialize_copy(other)\n      super\n      populate_from(other)\n    end\n\n    def populate_from(hash)\n      hash.each_pair { |k, v| self[k] = v }\n      self\n    end\n\n    def validate_options_hash!(options)\n      if (initial_capacity = options[:initial_capacity]) && (!initial_capacity.kind_of?(Integer) || initial_capacity < 0)\n        raise ArgumentError, \":initial_capacity must be a positive Integer\"\n      end\n      if (load_factor = options[:load_factor]) && (!load_factor.kind_of?(Numeric) || load_factor <= 0 || load_factor > 1)\n        raise ArgumentError, \":load_factor must be a number between 0 and 1\"","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby/concurrent/map.rb#L310-L346","documentation":"Concurrent::Map#fetch mirrors Hash#fetch: when the key is absent and neither a default value nor a block is supplied, it raises KeyError ('key not found') via the private raise_fetch_no_key (map.rb:338). It is deliberately stricter than Map#[], which returns nil (or the default proc result) for missing keys.","triggerScenarios":"map.fetch(:missing) with no default and no block; a key deleted by another thread between a key? check and the fetch; reading a registry/config Map before the writer thread has populated it.","commonSituations":"Treating fetch like []; startup-order races where a background writer has not yet stored the key; check-then-fetch (TOCTOU) patterns on a shared Map; code ported from Hash that relied on nil returns.","solutions":["Supply a default: map.fetch(key, default) or map.fetch(key) { compute }.","If nil is acceptable for missing keys, use map[key] instead of fetch.","Use map.fetch_or_store(key) { default } when you want atomic-ish read-or-populate.","When the key must exist, fix the ordering so the writer runs before any reader."],"exampleFix":"# before\nport = services.fetch(:db) # KeyError: key not found if not yet registered\n\n# after\nport = services.fetch(:db) { default_db_port } # or services[:db] when nil is acceptable","handlingStrategy":"validation","validationCode":"value = map.key?(key) ? map.fetch(key) : default_value\n# note: not atomic under concurrent deletes; fetch(key, default) is safer","typeGuard":null,"tryCatchPattern":"begin\n  map.fetch(key)\nrescue KeyError\n  default_value\nend","preventionTips":["Default to fetch(key, default) where absence is normal.","Reserve bare fetch for keys that must exist; treat KeyError as a bug signal.","Use fetch_or_store for lazy initialization.","Do not rely on key?-then-fetch under concurrency; a delete can interleave."],"tags":["ruby","concurrent-map","keyerror","fetch","race-condition"],"backgroundTag":"hash-fetch-key-not-found","analyzedSha":"0b88d5ff75f69b3740c8f0868e76f833cb2fd45d","analyzedAt":"2026-08-21T20:12:56.291Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}