we-promise/sure · error · Error
bad_request
bad_request
Error message
Invalid account number format: #{account_number} What it means
Raised by sanitize_account_number! before any HTTP call: account_number must be present and match /\A[A-Za-z0-9]+\z/. Indexa Capital account numbers are 8-char alphanumeric codes like "LPYH3MCQ", and this guard protects the URL path of /accounts/{account_number}/fiscal-results, /portfolio and /performance from injection and malformed paths.
Source
Thrown at app/models/provider/indexa_capital.rb:106
def get_activities(account_number:, start_date: nil, end_date: nil)
Rails.logger.info "Provider::IndexaCapital - No activities endpoint available for Indexa Capital API"
[]
end
private
RETRYABLE_ERRORS = [
SocketError, Net::OpenTimeout, Net::ReadTimeout,
Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::ETIMEDOUT, EOFError
].freeze
MAX_RETRIES = 3
INITIAL_RETRY_DELAY = 2 # seconds
# Indexa Capital account numbers are 8-char alphanumeric (e.g., "LPYH3MCQ")
def sanitize_account_number!(account_number)
unless account_number.present? && account_number.match?(/\A[A-Za-z0-9]+\z/)
raise Error.new("Invalid account number format: #{account_number}", :bad_request)
end
end
attr_reader :username, :document, :password, :api_token
def validate_configuration!
return if @api_token.present?
if @username.blank? || @document.blank? || @password.blank?
raise ConfigurationError, "Either API token or all three username/document/password credentials are required"
end
end
def token_auth?
@api_token.present?
end
def with_retries(operation_name, max_retries: MAX_RETRIES)View on GitHub (pinned to e69894adb9)
Solutions
- Always source the value from list_accounts/extract_accounts output (the account_number key), never from user input or cross-provider IDs
- Strip whitespace when storing: account_number.to_s.strip
- Pre-validate with the same regex before entering a sync loop so bad records are skipped/logged, not fatal
- If a legitimate account number ever contains a dash, loosen the regex deliberately - but confirm with Indexa first
Example fix
# before provider.get_holdings(account_number: account.external_id) # UUID like "0f8a..." # after provider.get_holdings(account_number: account.account_number.to_s.strip) # "LPYH3MCQ"
Defensive patterns
Strategy: validation
Validate before calling
INDEXA_ACCOUNT_NUMBER = /\A[A-Za-z0-9]{8}\z/ # provider requires alphanumeric
return unless (num = account_number.to_s.strip).match?(INDEXA_ACCOUNT_NUMBER)
provider.get_holdings(account_number: num) Type guard
def valid_indexa_account_number?(value)
value.to_s.strip.match?(/\A[A-Za-z0-9]{8}\z/)
end Try / catch
begin
provider.get_holdings(account_number: num)
rescue Provider::IndexaCapital::Error => e
raise unless e.error_type == :bad_request && e.message.include?("Invalid account number format")
account.update!(sync_disabled: true, disable_reason: "bad_account_number")
end Prevention
- Only use account_number values returned by list_accounts - never UUIDs, IBANs or names
- Strip whitespace at write time (account_number = value.to_s.strip)
- Validate the format before sync loops so one bad record doesn't abort the batch
- Never widen the regex without confirming the real format with Indexa
When it happens
Trigger: Passing nil/blank; passing an internal UUID or IBAN from another provider's account record; whitespace or a trailing newline in the stored account number; a hyphenated or formatted code copied from a statement PDF.
Common situations: Mapping accounts between providers by the wrong identifier, account_number column polluted with display names or whitespace from an import, calling get_holdings with the account 'name' instead of the 'account_number' field returned by list_accounts.
Related errors
- Either API token or all three username/document/password cre
- {result.error}
- {e.record.errors.full_messages.to_sentence.presence || e.mes
- invalid_response
- bad_request
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/d8ee219871dd0cef.
Report an issue: GitHub.