{"record":{"id":"174cc1a873dc5700","repo":"ruby-concurrency/concurrent-ruby","slug":"levels-has-to-be-higher-than-0","errorCode":null,"errorMessage":"levels has to be higher than 0","messagePattern":"levels has to be higher than 0","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby/concurrent/promises.rb","lineNumber":1884,"sourceCode":"          when AbstractEventFuture\n            add_delayed_of value\n            value.add_callback_notify_blocked self, nil\n            countdown\n          else\n            resolve_with RESOLVED\n          end\n        end\n        countdown\n      end\n\n    end\n\n    class FlatFuturePromise < AbstractFlatPromise\n\n      private\n\n      def initialize(delayed, blockers_count, levels, default_executor)\n        raise ArgumentError, 'levels has to be higher than 0' if levels < 1\n        # flat promise may result to a future having delayed futures, therefore we have to have empty stack\n        # to be able to add new delayed futures\n        super delayed || LockFreeStack.new, 1 + levels, Future.new(self, default_executor)\n      end\n\n      def process_on_blocker_resolution(future, index)\n        countdown = super(future, index)\n        if countdown.nonzero?\n          internal_state = future.internal_state\n\n          unless internal_state.fulfilled?\n            resolve_with internal_state\n            return countdown\n          end\n\n          value = internal_state.value\n          case value\n          when AbstractEventFuture","sourceCodeStart":1866,"sourceCodeEnd":1902,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby/concurrent/promises.rb#L1866-L1902","documentation":"Future#flat_future (alias flat, promises.rb:1126) flattens nested futures up to `level` levels deep. FlatFuturePromise#initialize (promises.rb:1886) requires level >= 1 and raises ArgumentError 'levels has to be higher than 0' otherwise, because a flattening of depth zero is meaningless.","triggerScenarios":"future.flat(0) or future.flat_future(0); a dynamically computed level reaching 0, e.g. levels = depth - 1 applied to a future nested one level; configuration defaulting a missing depth to 0 instead of 1.","commonSituations":"Generic flattening helpers where nesting depth is computed from data; off-by-one confusion about whether level counts layers inclusively; defaults from config files.","solutions":["Pass a level of at least 1; use bare flat (defaults to 1) for a single nesting layer.","Clamp computed levels: f.flat([computed_level, 1].max).","Validate the depth in your own helper before delegating to flat_future."],"exampleFix":"# before\nf.flat(depth - 1) # depth == 1 -> flat(0) -> ArgumentError\n\n# after\nf.flat([depth - 1, 1].max)","handlingStrategy":"validation","validationCode":"def flatten(future, level)\n  future.flat([level.to_i, 1].max) # never pass a level below 1\nend","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat 1 as the minimum flatten level; assert computed depths before calling flat.","Use bare flat (default level 1) unless you knowingly have deeper nesting.","Cover depth edge cases (0, negative) in tests for generic flattening helpers."],"tags":["ruby","concurrency","promises","argumenterror","validation"],"backgroundTag":"argument-out-of-range","analyzedSha":"0b88d5ff75f69b3740c8f0868e76f833cb2fd45d","analyzedAt":"2026-08-21T20:12:56.291Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}