thoughtbot/factory_bot · error · FactoryBot::InvalidFactoryError

The following factories are invalid: #{lines.join("\n")}

Error message

The following factories are invalid:

#{lines.join("\n")}

What it means

InvalidFactoryError raised by FactoryBot.lint (Linter#lint!, linter.rb:11-15). The linter instantiates every registered factory — and each trait when traits: true — using the chosen strategy (default :create), wrapped in a rollback transaction when ActiveRecord is defined, collects all failures, and raises one aggregate error. Each line of the message is `* factory_name - wrapped message (ErrorClass)` (or `factory+trait`) so the per-factory root causes are listed.

Source

Thrown at lib/factory_bot/linter.rb:13

module FactoryBot
  class Linter
    def initialize(factories, strategy: :create, traits: false, verbose: false)
      @factories_to_lint = factories
      @factory_strategy = strategy
      @traits = traits
      @verbose = verbose
      @invalid_factories = calculate_invalid_factories
    end

    def lint!
      if invalid_factories.any?
        raise InvalidFactoryError, error_message
      end
    end

    private

    attr_reader :factories_to_lint, :invalid_factories, :factory_strategy

    def calculate_invalid_factories
      factories_to_lint.each_with_object(Hash.new([])) do |factory, result|
        errors = lint(factory)
        result[factory] |= errors unless errors.empty?
      end
    end

    class FactoryError
      def initialize(wrapped_error, factory)
        @wrapped_error = wrapped_error
        @factory = factory

View on GitHub (pinned to 18ae8b581b)

Solutions

  1. Read the per-line wrapped errors in the message — each names the factory, the underlying exception message, and its class; fix those factories first.
  2. Re-run with verbose: true for full backtraces and traits: true to cover trait failures.
  3. Fix root causes: add required attributes/transients after model changes, correct association targets, repair sequences.
  4. Keep the lint task in CI so invalid factories fail the build before developers hit them at runtime.

Example fix

# before
factory :user do
  name { 'Alice' } # email column added + presence validation -> factory fails lint
end

# after
factory :user do
  name { 'Alice' }
  email { sequence(:email) { |n| "alice#{n}@example.com" } }
end
Defensive patterns

Strategy: try-catch

Validate before calling

# lint only the factories touched by a change, before running the full suite
FactoryBot.lint(FactoryBot.factories.select { |f| f.name.to_s.start_with?('user') })

Try / catch

begin
  FactoryBot.lint(traits: true, verbose: true)
rescue FactoryBot::InvalidFactoryError => e
  warn e.message # lists each factory, wrapped message, and error class
  exit 1
end

Prevention

When it happens

Trigger: Run `FactoryBot.lint` or `FactoryBot.lint!(traits: true, verbose: true)` (typically a CI rake task); any factory whose build/create raises — model validations, missing columns after a migration, associations pointing at undefined factories, broken sequences — is aggregated into 'The following factories are invalid:' with one line per failure.

Common situations: Schema drift: factories not updated after migrations or new validations (presence/uniqueness breaking old factories); a factory renamed or deleted while associations still reference it; trait combinations never exercised by the test suite; linting newly enabled on a legacy codebase for the first time.

Related errors


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