antiwork/gumroad · error · StripeBeneficialOwnersManager::MissingRequiredFieldError

#{missing.to_sentence} #{missing.length == 1 ? "is" : "are"}

Error message

#{missing.to_sentence} #{missing.length == 1 ? "is" : "are"} required for beneficial owners — Stripe needs them to verify the person.

What it means

MissingRequiredFieldError from StripeBeneficialOwnersManager.validate_required_fields! during Stripe merchant (connected-account) onboarding. It aggregates every empty required beneficial-owner field — the base set, plus create-only fields when action == :create, plus Nationality for countries in COUNTRIES_REQUIRING_NATIONALITY, plus Ownership percentage when params[:owner] is truthy — and raises one message listing all of them ("X, Y and Z are required for beneficial owners…"). It runs before any Stripe API call so Stripe never receives an incomplete Person.

Source

Thrown at app/business/payments/merchant_registration/implementations/stripe/stripe_beneficial_owners_manager.rb:163

          label if address[key].to_s.strip.empty?
        end
      end
    elsif action == :create
      missing += is_jp_seller ? REQUIRED_JP_ADDRESS_FIELDS.values : REQUIRED_ADDRESS_FIELDS.values
    end
    if action == :create
      missing += REQUIRED_CREATE_ONLY_FIELDS.filter_map do |key, label|
        label if params[key].to_s.strip.empty?
      end
    end
    if action == :create && COUNTRIES_REQUIRING_NATIONALITY.include?(seller_country) && params[:nationality].to_s.strip.empty?
      missing << "Nationality"
    end
    if truthy?(params[:owner]) && params[:percent_ownership].to_s.strip.empty?
      missing << "Ownership percentage"
    end
    return if missing.empty?
    raise MissingRequiredFieldError, "#{missing.to_sentence} #{missing.length == 1 ? "is" : "are"} required for beneficial owners — Stripe needs them to verify the person."
  end
  private_class_method :validate_required_fields!

  def self.required_address_fields_for(country_code)
    fields = REQUIRED_ADDRESS_FIELDS
    fields = fields.except(:postal_code) if COUNTRIES_WITHOUT_POSTAL_CODE.include?(country_code)
    fields = fields.except(:state) unless COUNTRIES_WITH_STATE_LIST.include?(country_code)
    fields
  end
  private_class_method :required_address_fields_for

  # Server-side counterpart of the kana-format checks the beneficial-owner form runs in the
  # browser. Without this, a direct API request could put non-katakana text in a kana field
  # and we would forward it to Stripe as address_kana/first_name_kana, which Stripe rejects
  # for Japanese accounts. Reuses the same regexes UserComplianceInfo applies to the
  # seller's own kana fields.
  def self.validate_jp_kana_address_format!(params, user)
    validate_kana_param!(params[:first_name_kana], "First name (Kana)", UserComplianceInfo::KANA_NAME_REGEX, "katakana characters, spaces, dashes, and dots")

View on GitHub (pinned to afeacbd394)

Solutions

  1. Fill in every field named in the message — the error already enumerates exactly which labels are missing; resubmit with those keys non-blank.
  2. Check action semantics: on :create the REQUIRED_CREATE_ONLY_FIELDS are also mandatory; on :update only the base set is, so an update failing means a base field is blank.
  3. Send percent_ownership whenever owner is truthy in your payload semantics (and send a real boolean, not the string "false", if ownership is not claimed).
  4. For sellers in nationality-requiring countries, make the nationality input required in the UI for create.

Example fix

# before: owner flagged without ownership share
StripeBeneficialOwnersManager.create_person({ owner: true, first_name: "A", last_name: "B", dob: "1990-01-01" }, user)
# after: include every required field for create
StripeBeneficialOwnersManager.create_person({ owner: true, percent_ownership: "55", first_name: "A", last_name: "B", dob: "1990-01-01", nationality: "JP", address: {...} }, user)
Defensive patterns

Strategy: validation

Validate before calling

missing = REQUIRED_FIELDS.select { |k, _| params[k].to_s.strip.empty? }.map(&:last)
missing += ["Ownership percentage"] if truthy_owner_without_percent?(params)
return Result.invalid(missing) unless missing.empty?

Type guard

def beneficial_owner_params_complete?(params, action:, seller_country:)
  keys = StripeBeneficialOwnersManager::REQUIRED_FIELDS.keys
  keys += StripeBeneficialOwnersManager::REQUIRED_CREATE_ONLY_FIELDS.keys if action == :create
  keys.all? { |k| params[k].to_s.strip.present? } &&
    !(truthy?(params[:owner]) && params[:percent_ownership].to_s.strip.empty?)
end

Prevention

When it happens

Trigger: POSTing/PATCHing beneficial-owner person params via the merchant-registration flow (create or update) with any required key blank: e.g. creating an owner without first/last name, dob, or address lines; creating for a JP/other nationality-required country with params[:nationality] empty; marking owner=true (truthy) without percent_ownership.

Common situations: Front-end form skipping fields conditionally (e.g. hiding nationality for non-US/JP and forgetting the create-only set); API integrations not sending percent_ownership when relationship.owner is set; update calls assuming create-only fields aren't needed (they are only checked on :create — blanks on update pass); truthiness traps where params[:owner] is the string "false" and still counts as truthy.

Related errors


AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21). Data as JSON: /api/errors/4862ccace4a0e26c. Report an issue: GitHub.