thoughtbot/factory_bot · error · ArgumentError

Sequence '#{sequence.uri_manager.first}' failed to return a

Error message

Sequence '#{sequence.uri_manager.first}' failed to return a value. Perhaps it needs a scope to operate? (scope: <object>)

What it means

ArgumentError raised by the private Syntax::Methods#increment_sequence (methods.rb:169-178) that backs the public generate/generate_list API. Here scope defaults to nil, so a sequence block written against instance state (`sequence(:info) { |n| "#{name}:#{age + n}" }`) executes with no scope and fails; the bare rescue rewrites any exception from sequence.next into this generic ArgumentError, naming the sequence's URI from sequence.uri_manager (e.g. 'user/info'). The underlying exception is hidden.

Source

Thrown at lib/factory_bot/syntax/methods.rb:176

      private

      ##
      # Increments the given sequence and returns the value.
      #
      # Arguments:
      #   sequence:
      #     The sequence instance
      #   scope: (object)(optional)
      #     The object the sequence should be evaluated within
      #
      def increment_sequence(sequence, scope: nil)
        value = sequence.next(scope)

        raise if value.respond_to?(:start_with?) && value.start_with?("#<FactoryBot::Declaration")

        value
      rescue
        raise ArgumentError, "Sequence '#{sequence.uri_manager.first}' failed to " \
                            "return a value. Perhaps it needs a scope to operate? (scope: <object>)"
      end
    end
  end
end

View on GitHub (pinned to 18ae8b581b)

Solutions

  1. Pass an explicit scope that provides every method the block references: `generate(:user, :info, scope: user)`.
  2. If the sequence should be stateless, rewrite it to use only the counter: `sequence(:info) { |n| "user-#{n}" }`.
  3. For lists, thread the same scope: `generate_list(:user, :info, 5, scope: user)`.
  4. While debugging, call the sequence directly (e.g. `FactoryBot::Sequence.find(:user, :info).next(user)`) to see the original exception before factory_bot rewrites it.

Example fix

# before
generate(:user, :info) # ArgumentError: state-dependent sequence, no scope

# after
user = build(:user, name: 'Jester', age: 21)
generate(:user, :info, scope: user)
Defensive patterns

Strategy: validation

Validate before calling

# wrapper that refuses scope-less calls to state-dependent sequences
def generate_scoped!(*uri, scope:)
  raise ArgumentError, 'scope: is required for this sequence' if scope.nil?
  generate(*uri, scope: scope)
end

Type guard

->(scope) { !scope.nil? }

Try / catch

begin
  generate(:user, :info)
rescue ArgumentError => e
  raise unless e.message.include?('failed to return a value')
  # either pass scope: or rewrite the sequence to be self-contained
end

Prevention

When it happens

Trigger: Per spec/acceptance/sequence_spec.rb:203-219: define `factory :user do sequence(:info) { |n| "#{name}:#{age + n}" } end`; then `generate(:user, :info)` raises "Sequence 'user/info' failed to return a value. Perhaps it needs a scope to operate?", while `generate(:user, :info, scope: jester)` with an object that has name/age succeeds. Any other exception inside the block (typo, nil arithmetic) reached via generate/generate_list produces the same error.

Common situations: Calling global generate for a sequence originally written against factory instance state; refactoring an inline factory sequence into a shared/global one; NoMethodError-on-nil hidden by the generic message, making failures hard to diagnose in CI.

Related errors


AI-assisted analysis of thoughtbot/factory_bot@18ae8b581b (2026-08-21). Data as JSON: /api/errors/18dae8062bfa0e20. Report an issue: GitHub.