{"record":{"id":"1cb816d5d8046330","repo":"ruby-concurrency/concurrent-ruby","slug":"it-is-not-rejected","errorCode":null,"errorMessage":"it is not rejected","messagePattern":"it is not rejected","errorType":"exception","errorClass":"Concurrent::Error","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby/concurrent/promises.rb","lineNumber":1015,"sourceCode":"      # @raise [Exception] {#reason} on rejection\n      def value!(timeout = nil, timeout_value = nil)\n        if wait_until_resolved! timeout\n          internal_state.value\n        else\n          timeout_value\n        end\n      end\n\n      # Allows rejected Future to be risen with `raise` method.\n      # If the reason is not an exception `Runtime.new(reason)` is returned.\n      #\n      # @example\n      #   raise Promises.rejected_future(StandardError.new(\"boom\"))\n      #   raise Promises.rejected_future(\"or just boom\")\n      # @raise [Concurrent::Error] when raising not rejected future\n      # @return [Exception]\n      def exception(*args)\n        raise Concurrent::Error, 'it is not rejected' unless rejected?\n        raise ArgumentError unless args.size <= 1\n        reason = Array(internal_state.reason).flatten.compact\n        callsites = SET_BACKTRACE_LOCATIONS_SUPPORTED ? caller_locations : caller\n        if reason.size > 1\n          ex = Concurrent::MultipleErrors.new reason\n          ex.set_backtrace(callsites)\n          ex\n        else\n          ex = if reason[0].respond_to? :exception\n                 reason[0].exception(*args)\n               else\n                 RuntimeError.new(reason[0]).exception(*args)\n               end\n          if SET_BACKTRACE_LOCATIONS_SUPPORTED && (locations = ex.backtrace_locations)\n            ex.set_backtrace locations + callsites\n          else\n            ex.set_backtrace Array(ex.backtrace) + callsites.map(&:to_s)\n          end","sourceCodeStart":997,"sourceCodeEnd":1033,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby/concurrent/promises.rb#L997-L1033","documentation":"Future#exception (promises.rb:1011-1016) exists so a rejected future can be used with raise (Ruby's raise calls obj.exception). It requires the future to be rejected; when called on a pending or fulfilled future it raises Concurrent::Error 'it is not rejected' (promises.rb:1015). It is a state precondition on the future, not a general accessor for the result.","triggerScenarios":"raise future where the future fulfilled successfully; future.exception called explicitly on a pending or fulfilled future; generic error-propagation code that re-raises whatever future it receives without checking rejected?.","commonSituations":"Writing `raise future` plumbing in rescue handlers; helpers that turn outcomes into exceptions without branching on state; testing rejection paths with futures that actually fulfilled.","solutions":["Check state first: future.wait!; raise future only if future.rejected?.","Prefer future.value! — it returns the value when fulfilled and raises the rejection reason when rejected, no precondition needed.","Use future.result ([:ok/:error, value, reason]) for explicit branching instead of raise."],"exampleFix":"# before\nraise future # Concurrent::Error: it is not rejected (future was fulfilled)\n\n# after\nfuture.wait!\nraise future if future.rejected?\n# or simply:\nfuture.value! # returns value, or raises the rejection reason","handlingStrategy":"validation","validationCode":"future.wait!\nraise future.exception if future.rejected? # only raise after confirming rejection","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Branch on rejected?/fulfilled? before converting a future to an exception.","Prefer future.value! or future.result over raise future for outcome propagation.","Ensure futures are resolved (wait!) before inspecting their state in assertions."],"tags":["ruby","concurrency","promises","future","state-machine"],"backgroundTag":"raise-non-rejected-promise","analyzedSha":"0b88d5ff75f69b3740c8f0868e76f833cb2fd45d","analyzedAt":"2026-08-21T20:12:56.291Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}