we-promise/sure · error · IbkrItem::ReportParser::ParseError
Invalid IBKR Flex XML: #{e.message}
Error message
Invalid IBKR Flex XML: #{e.message} What it means
IbkrItem::ReportParser parses the Flex Query response with Nokogiri in strict mode (config.strict.noblanks); any XML::SyntaxError is converted to ParseError with the underlying parser message. The parser expects well-formed IBKR Flex XML — HTML pages or plain-text error bodies fail here.
Source
Thrown at app/models/ibkr_item/report_parser.rb:22
class ParseError < StandardError; end
POSITION_VALUE_CONTAINER_NAMES = %w[ChangeInPositionValues].freeze
POSITION_VALUE_ROW_NAMES = %w[ChangeInPositionValue].freeze
CASH_REPORT_CONTAINER_NAMES = %w[CashReport CashReports].freeze
CASH_REPORT_ROW_NAMES = %w[CashReport CashReportCurrency CashReportRow].freeze
EQUITY_SUMMARY_CONTAINER_NAMES = %w[EquitySummaryInBase].freeze
EQUITY_SUMMARY_ROW_NAMES = %w[EquitySummaryByReportDateInBase].freeze
OPEN_POSITION_CONTAINER_NAMES = %w[OpenPositions].freeze
OPEN_POSITION_ROW_NAMES = %w[OpenPosition].freeze
TRADES_CONTAINER_NAMES = %w[Trades].freeze
TRADE_ROW_NAMES = %w[Trade].freeze
CASH_TRANSACTION_CONTAINER_NAMES = %w[CashTransactions].freeze
CASH_TRANSACTION_ROW_NAMES = %w[CashTransaction].freeze
def initialize(xml_body)
@document = Nokogiri::XML(xml_body.to_s) { |config| config.strict.noblanks }
rescue Nokogiri::XML::SyntaxError => e
raise ParseError, "Invalid IBKR Flex XML: #{e.message}"
end
def parse
validate_document!
{
metadata: root_metadata,
accounts: flex_statements.map { |statement| parse_statement(statement) }
}
end
private
def validate_document!
raise ParseError, "Invalid IBKR Flex XML: missing FlexQueryResponse root." unless @document.at_xpath("//FlexQueryResponse")
raise ParseError, "Invalid IBKR Flex XML: no FlexStatement nodes found." if flex_statements.empty?
end
View on GitHub (pinned to e69894adb9)
Solutions
- Capture the raw body passed to the parser and check it standalone (xmllint) to locate the syntax error position
- If the body is an HTML/text error page, fix the upstream request (token, query id) so IBKR returns the actual Flex report
- Rescue IbkrItem::ReportParser::ParseError around the import to fail the sync with a user-safe message and log the body for triage
Example fix
begin data = IbkrItem::ReportParser.new(body).parse rescue IbkrItem::ReportParser::ParseError => e DebugLogEntry.capture(category: 'ibkr', level: 'error', message: e.message, source: 'IbkrItem::ReportParser') raise end
Defensive patterns
Strategy: try-catch
Try / catch
rescue IbkrItem::ReportParser::ParseError => e around ReportParser.new(body).parse; capture the raw body length/first bytes in a DebugLogEntry, then fail the sync with a user-safe message
Prevention
- Fetch Flex reports with explicit charset handling and response-body logging at debug level
- Never feed unverified HTML/error pages to the strict parser
- Record the token/query id used per fetch so malformed responses can be correlated with credentials
When it happens
Trigger: Feeding ReportParser.new(xml_body) a malformed document: a truncated download, an HTML error page saved as the report, encoding corruption, or a test stub returning non-XML.
Common situations: IBKR returning an error page instead of the report for bad tokens; proxies or middlewares truncating responses; hand-edited fixtures that are no longer valid XML.
Related errors
- Invalid IBKR Flex XML: missing FlexQueryResponse root.
- Invalid IBKR Flex XML: no FlexStatement nodes found.
- Invalid IBKR Flex XML: missing account identifier in FlexSta
- IBKR Flex did not return a reference code.
- IBKR provider is not configured
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/68209c02c2357678.
Report an issue: GitHub.