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 = factoryView on GitHub (pinned to 18ae8b581b)
Solutions
- Read the per-line wrapped errors in the message — each names the factory, the underlying exception message, and its class; fix those factories first.
- Re-run with verbose: true for full backtraces and traits: true to cover trait failures.
- Fix root causes: add required attributes/transients after model changes, correct association targets, repair sequences.
- 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
- Add a factory_bot:lint rake task to CI so schema/factory drift fails the build early.
- Run with traits: true and verbose: true locally to see backtraces and trait failures.
- Update factories in the same PR that changes models, validations, or migrations.
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
- Association '#{name}' received an invalid factory argument.
- Association '#{name}' received an invalid attribute override
- undefined method '#{name}' in '#{@definition.name}' factory
- Unexpected block passed to '#{name}' association in '#{@defi
- Attribute already defined: #{attribute.name}
AI-assisted analysis of thoughtbot/factory_bot@18ae8b581b (2026-08-21).
Data as JSON: /api/errors/3b40d70a33580b8d.
Report an issue: GitHub.