thoughtbot/factory_bot · error · FactoryBot::AssociationDefinitionError
Unexpected block passed to '#{name}' association in '#{@defi
Error message
Unexpected block passed to '#{name}' association in '#{@definition.name}' factory What it means
AssociationDefinitionError raised by DefinitionProxy#association (definition_proxy.rb:155-160) when a block is passed to `association`. Associations are purely declarative; factory_bot cannot evaluate a block for them, and the guard fails fast during the FactoryBot.define block instead of silently ignoring the block.
Source
Thrown at lib/factory_bot/definition_proxy.rb:157
#
# factory :post do
# association :author, factory: :user
# end
#
# Arguments:
# * name: +Symbol+
# The name of this attribute.
# * options: +Hash+
#
# Options:
# * factory: +Symbol+ or +String+
# The name of the factory to use when building the associated instance.
# If no name is given, the name of the attribute is assumed to be the
# name of the factory. For example, a "user" association will by
# default use the "user" factory.
def association(name, *options)
if block_given?
raise AssociationDefinitionError.new(
"Unexpected block passed to '#{name}' association " \
"in '#{@definition.name}' factory"
)
else
declaration = Declaration::Association.new(name, *options)
@definition.declare_attribute(declaration)
end
end
def to_create(&block)
@definition.to_create(&block)
end
def skip_create
@definition.skip_create
end
def factory(name, options = {}, &block)View on GitHub (pinned to 18ae8b581b)
Solutions
- Remove the block and pass overrides directly: `association :author, factory: :user, name: 'Jane'`.
- Move the customization into a trait on the target factory and pass the trait: `association :author, :with_name, factory: :user`.
- Use after(:build) / after(:create) callbacks on the parent factory to mutate the associated record.
- If you need dynamic construction, use the allowed block form `author { association(:author, name: 'Jane') }` — a Dynamic attribute whose block calls association.
Example fix
# before
FactoryBot.define do
factory :post do
association :author, factory: :user do |author|
author.name = 'Jane'
end
end
end
# after
FactoryBot.define do
factory :post do
association :author, factory: :user, name: 'Jane'
end
end Defensive patterns
Strategy: validation
Validate before calling
# wrapper that refuses blocks on associations before factory_bot sees them
def association!(name, *options, &block)
raise ArgumentError, "association #{name} takes no block" if block
association(name, *options)
end Type guard
->(blk) { blk.nil? } Try / catch
begin
FactoryBot.define { #...
}
rescue FactoryBot::AssociationDefinitionError => e
raise unless e.message.include?('Unexpected block passed')
# move the block body into overrides, a trait, or an after(:build) callback
end Prevention
- Keep `association` declarations one-line; put customization in traits or callbacks.
- Use `attr { association(:x, ...) }` when association construction must be dynamic.
- Treat the create-block habit (`create(:x) { |o| ... }`) as call-site only — never inside definitions.
When it happens
Trigger: Write `association :author, factory: :user do |a| ... end` (or the short form `author factory: :user do ... end`) inside a factory body. The definition block raises immediately with "Unexpected block passed to 'author' association in 'post' factory".
Common situations: Trying to customize the associated record inline, a habit carried over from `create(:user) { |u| ... }` result blocks; converting an attribute block into an association while leaving the block attached; refactoring shared setups where the block contained extra attribute assignments.
Related errors
- Association '#{name}' received an invalid factory argument.
- Association '#{name}' received an invalid attribute override
- Self-referencing association '#{attribute.name}' in '#{attri
- Defining methods in blocks (trait or factory) is not support
- undefined method '#{name}' in '#{@definition.name}' factory
AI-assisted analysis of thoughtbot/factory_bot@18ae8b581b (2026-08-21).
Data as JSON: /api/errors/2a7e07edb8d33a27.
Report an issue: GitHub.