{"record":{"id":"be1e0473dd6886f4","repo":"ruby-concurrency/concurrent-ruby","slug":"concurrent-multipleassignmenterror","errorCode":null,"errorMessage":"Concurrent::MultipleAssignmentError","messagePattern":"Concurrent::MultipleAssignmentError","errorType":"exception","errorClass":"Concurrent::MultipleAssignmentError","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby/concurrent/ivar.rb","lineNumber":115,"sourceCode":"\n      observer.send(func, Time.now, self.value, reason) if direct_notification\n      observer\n    end\n\n    # @!macro ivar_set_method\n    #   Set the `IVar` to a value and wake or notify all threads waiting on it.\n    #\n    #   @!macro ivar_set_parameters_and_exceptions\n    #     @param [Object] value the value to store in the `IVar`\n    #     @yield A block operation to use for setting the value\n    #     @raise [ArgumentError] if both a value and a block are given\n    #     @raise [Concurrent::MultipleAssignmentError] if the `IVar` has already\n    #       been set or otherwise completed\n    #\n    #   @return [IVar] self\n    def set(value = NULL)\n      check_for_block_or_value!(block_given?, value)\n      raise MultipleAssignmentError unless compare_and_set_state(:processing, :pending)\n\n      begin\n        value = yield if block_given?\n        complete_without_notification(true, value, nil)\n      rescue => ex\n        complete_without_notification(false, nil, ex)\n      end\n\n      notify_observers(self.value, reason)\n      self\n    end\n\n    # @!macro ivar_fail_method\n    #   Set the `IVar` to failed due to some error and wake or notify all threads waiting on it.\n    #\n    #   @param [Object] reason for the failure\n    #   @raise [Concurrent::MultipleAssignmentError] if the `IVar` has already\n    #     been set or otherwise completed","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby/concurrent/ivar.rb#L97-L133","documentation":"An IVar is a write-once container. IVar#set first flips state from :pending to :processing with an atomic compare-and-set (ivar.rb:115); if the IVar is already fulfilled or rejected, or another writer currently holds :processing, the CAS fails and Concurrent::MultipleAssignmentError (errors.rb:33) is raised. The library enforces single assignment instead of silently overwriting the value.","triggerScenarios":"Calling ivar.set(1) twice; calling #set after #fail; two threads racing to set the same IVar where the loser raises; setting an IVar that a framework component (dataflow graph, actor handler, promise adapter) already completed.","commonSituations":"Request/response handoffs where both a timeout timer and the response path try to complete the same IVar; worker fan-in where several workers write one result slot; retry logic that re-sets the IVar after a failed attempt.","solutions":["Use ivar.try_set(value) (ivar.rb:145): it swallows MultipleAssignmentError and returns true/false, which is exactly the race-safe guard for competing writers.","Check ivar.incomplete? before #set to catch the common sequential double-set.","Restructure so exactly one completion path exists (cancel the timeout when the response wins).","Rescue Concurrent::MultipleAssignmentError when losing a race is expected and the first result should stand."],"exampleFix":"# before\nivar.set(response) # raises MultipleAssignmentError if timeout path completed first\n\n# after\nivar.try_set(response) # returns false when already completed; no exception","handlingStrategy":"validation","validationCode":"ivar.set(response) if ivar.incomplete? # best-effort sequential guard\n# for real multi-writer races use the built-in race-safe form:\nivar.try_set(response)","typeGuard":null,"tryCatchPattern":"begin\n  ivar.set(value)\nrescue Concurrent::MultipleAssignmentError\n  # first writer won; keep its value\nend","preventionTips":["Prefer try_set whenever more than one path can complete the IVar.","Give each IVar a single owner; make timeout and response paths mutually exclusive.","Treat MultipleAssignmentError in sequential code as a logic bug, not a retryable failure."],"tags":["concurrency","ruby","ivar","write-once","race-condition"],"backgroundTag":"write-once-violation","analyzedSha":"0b88d5ff75f69b3740c8f0868e76f833cb2fd45d","analyzedAt":"2026-08-21T20:12:56.291Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}