spree/spree · warning
Spree::Dependencies##{legacy}= is deprecated and NO LONGER C
Error message
Spree::Dependencies##{legacy}= is deprecated and NO LONGER CONSULTED by Spree — the override was not applied. Port the class to the #{current} contract and set #{current}= instead. The #{legacy} name is removed in Spree 6.1. What it means
In 6.0 the service tier seams became workflow seams (Spree::Workflow classes with named steps). A legacy writer such as Spree::Dependencies.cart_add_item_service = 'MyService' warns with this message and STASHES the value in legacy_workflow_overrides - the override is NOT applied to the workflow seam, because a class written against the old service contract is not interchangeable with the workflow the new call sites consume. Legacy readers return the stash (so legacy code calling its own class keeps working), falling back to the workflow class. Affected keys: cart_add_item_service, cart_recalculate_service, cart_merge_strategy, carts_complete_service, carts_upsert_items_service, payments_handle_webhook_service, fulfillment_create_service, order_cancel_service, order_complete_service, shipment_update_service, fulfillment_update_service, gift_card_apply_service, gift_card_remove_service, gift_card_redeem_service. Removed in Spree 6.1.
Source
Thrown at spree/core/lib/spree/core/dependencies.rb:280
# Spree.<name> resolves through <name>_class, so the rename needs the
# constantized reader too.
define_method("#{legacy}_class") do
Spree::Deprecation.warn(
"Spree::Dependencies##{legacy} is deprecated and will be removed in Spree 6.1. " \
"Use #{current} instead."
)
send("#{current}_class")
end
end
def legacy_workflow_overrides
@legacy_workflow_overrides ||= {}
end
LEGACY_WORKFLOW_KEYS.merge(LEGACY_SERVICE_KEYS).each do |legacy, current|
define_method("#{legacy}=") do |value|
Spree::Deprecation.warn(
"Spree::Dependencies##{legacy}= is deprecated and NO LONGER CONSULTED by Spree — " \
"the override was not applied. Port the class to the #{current} contract and " \
"set #{current}= instead. The #{legacy} name is removed in Spree 6.1."
)
legacy_workflow_overrides[legacy] = value
end
define_method(legacy) do
Spree::Deprecation.warn("Spree::Dependencies##{legacy} is deprecated and will be removed in Spree 6.1. Use #{current} instead.")
legacy_workflow_overrides.fetch(legacy) { send(current) }
end
define_method("#{legacy}_class") do
Spree::Deprecation.warn("Spree::Dependencies##{legacy} is deprecated and will be removed in Spree 6.1. Use #{current} instead.")
if legacy_workflow_overrides.key?(legacy)
value = legacy_workflow_overrides[legacy]
value.is_a?(String) ? value.constantize : value
elseView on GitHub (pinned to 06bf66a868)
Solutions
- Port the custom class to the workflow contract: subclass Spree::Workflow, express the logic as step/external_step, accept the new keyword vocabulary (cart:, items:, fulfillment:, ...)
- Set the new seam in the initializer: Spree::Dependencies.cart_add_item_workflow = 'MyApp::Carts::AddItemWorkflow' (or the matching *_workflow key from the warning text)
- Delete the legacy assignment once ported - keep it only while other legacy code still reads the old key
- Add a spec asserting the workflow seam resolves to your class, so a silently-stashed override can never ship
Example fix
# before
Spree::Dependencies.cart_add_item_service = 'MyApp::Cart::AddItem' # warned AND ignored
# after
class MyApp::Carts::AddItemWorkflow < Spree::Workflow
def perform(cart:, variant:, quantity: nil, metadata: {}, options: {})
super
step :apply_loyalty_pricing
end
end
Spree::Dependencies.cart_add_item_workflow = 'MyApp::Carts::AddItemWorkflow' Defensive patterns
Strategy: validation
Validate before calling
# After boot, prove your override is live on the seam new call sites consume: expected = 'MyApp::Carts::AddItemWorkflow' raise 'override stashed, not applied' unless Spree::Dependencies.cart_add_item_workflow_class == expected
Prevention
- Never assume a deprecated writer still routes - this family stashes legacy overrides instead of applying them
- Add a seam-assertion spec for every customized Spree::Dependencies entry so a silent no-op fails CI
- When porting a service to a workflow, reuse the workflow's own specs (e.g. the Carts::AddItem battery) against your subclass
When it happens
Trigger: Running an initializer that sets any of the fourteen legacy *_service / cart_merge_strategy keys, e.g. Spree::Dependencies.cart_add_item_service = 'MyApp::Cart::AddItem'. The warning fires at boot, and the customized behavior silently stops being consulted by checkout, cart, webhook, fulfillment and gift-card flows.
Common situations: Apps upgraded from Spree 5.x that swapped checkout/cart services (custom add-item validation, custom completion, custom merge) and find the custom logic inactive after the upgrade; extensions installing overrides via generators; the trap is silent - everything still works, just with default behavior.
Related errors
- Spree::Dependencies##{legacy}= is deprecated and will be rem
- Spree::Dependencies##{legacy} is deprecated and will be remo
- Spree::Taxons::RemoveProducts is deprecated and will be remo
- Calling Spree::Carts::AddItem with order: is deprecated and
- Calling Spree::Carts::Recalculate with order: is deprecated
AI-assisted analysis of spree/spree@06bf66a868 (2026-08-21).
Data as JSON: /api/errors/1d165f37acce8059.
Report an issue: GitHub.