spree/spree · error · ArgumentError
Email is required
Error message
Email is required
What it means
Spree::Imports::RowProcessors::Customer#process! raises ArgumentError 'Email is required' when a customer-import CSV row has no usable email (blank after strip). Email is the find_or_initialize_by key on Spree.customer_class, so a row without it cannot identify or create a customer and the row is rejected before any attribute is assigned.
Source
Thrown at spree/core/app/services/spree/imports/row_processors/customer.rb:17
module Spree
module Imports
module RowProcessors
class Customer < Base
def process!
user = find_or_initialize_user
assign_user_attributes(user)
assign_address(user) if address_fields_present?
user.save!
user
end
private
def find_or_initialize_user
email = attributes['email'].to_s.strip.downcase
raise ArgumentError, 'Email is required' if email.blank?
Spree.customer_class.find_or_initialize_by(email: email)
end
def assign_user_attributes(user)
user.first_name = attributes['first_name'].strip if attributes['first_name'].present?
user.last_name = attributes['last_name'].strip if attributes['last_name'].present?
user.phone = attributes['phone'].strip if attributes['phone'].present?
user.accepts_email_marketing = to_boolean(attributes['accepts_email_marketing']) if attributes['accepts_email_marketing'].present?
user.tag_list = attributes['tags'] if attributes['tags'].present?
if user.new_record?
password = SecureRandom.hex(16)
user.password = password
user.password_confirmation = password
end
end
View on GitHub (pinned to 06bf66a868)
Solutions
- Open the CSV and confirm a header column named exactly 'email' exists.
- Fill in or remove every row whose email cell is empty or whitespace-only.
- Re-save the file as plain UTF-8 without BOM and strip stray whitespace from headers.
- Re-run the import; row-level failures are reported per row, so previously imported rows are not lost.
Example fix
# before — customers.csv first_name,last_name Ada,Lovelace # after email,first_name,last_name ada@example.com,Ada,Lovelace
Defensive patterns
Strategy: validation
Validate before calling
# before submitting a customers import, reject/repair rows without email
require 'csv'
invalid = []
CSV.table(csv_path, converters: nil).each.with_index(2) do |row, line|
invalid << line if row[:email].to_s.strip.blank?
end
abort "Rows without email: #{invalid.join(', ')}" if invalid.any? Try / catch
begin processor.process! rescue ArgumentError => e # per-row failure: record line + message, keep importing the rest import_row.update!(status: 'failed', error_message: e.message) end
Prevention
- Give merchants a downloadable CSV template with the email header pre-filled.
- Validate headers and required columns client-side (dashboard import wizard) before upload.
- Treat import failures as row-level: collect and surface line numbers instead of aborting the file.
When it happens
Trigger: Running a customers CSV import where the 'email' column is absent from the header, empty on some row, or contains only whitespace. The processor strips and downcases attributes['email'] and raises when the result is blank.
Common situations: Exported file with a renamed or mistyped header ('Email', 'e-mail', 'email '), spreadsheet saving blank cells as empty strings, UTF-8 BOM shifting the first header, or assuming email is optional because the storefront allows guest data without it.
Related errors
- Locale is required
- Slug is required
- Product slug is required for variant rows
- Request body is not valid JSON${where}
- Invalid -q expression "${expression}" — expected key=value (
AI-assisted analysis of spree/spree@06bf66a868 (2026-08-21).
Data as JSON: /api/errors/6b8f242eea11c396.
Report an issue: GitHub.