we-promise/sure · error · IbkrItem::ReportParser::ParseError
Invalid IBKR Flex XML: no FlexStatement nodes found.
Error message
Invalid IBKR Flex XML: no FlexStatement nodes found.
What it means
validate_document! raises when the document has a FlexQueryResponse root but zero //FlexStatement nodes. The envelope is correct but contains no account statements, so there is nothing to import and the parser refuses to return an empty account set as if it were valid.
Source
Thrown at app/models/ibkr_item/report_parser.rb:38
@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
def flex_statements
@document.xpath("//FlexStatement")
end
def root_metadata
node_attributes(@document.at_xpath("//FlexQueryResponse"))
end
def parse_statement(statement)
statement_data = node_attributes(statement)
account_information = node_attributes(statement.at_xpath("./AccountInformation"))
position_values = section_rows(statement, POSITION_VALUE_CONTAINER_NAMES, POSITION_VALUE_ROW_NAMES)
cash_report = section_rows(statement, CASH_REPORT_CONTAINER_NAMES, CASH_REPORT_ROW_NAMES)
equity_summary_in_base = section_rows(statement, EQUITY_SUMMARY_CONTAINER_NAMES, EQUITY_SUMMARY_ROW_NAMES)
open_positions = section_rows(statement, OPEN_POSITION_CONTAINER_NAMES, OPEN_POSITION_ROW_NAMES)
trades = section_rows(statement, TRADES_CONTAINER_NAMES, TRADE_ROW_NAMES)View on GitHub (pinned to e69894adb9)
Solutions
- Verify the Flex Query (query_id) in IBKR Portal includes the statement types and date range you expect
- Retry later — Flex report data can lag behind token/query creation
- Distinguish this from parse failures when rescuing: an empty-statement document means configuration/timing, not corruption
Defensive patterns
Strategy: try-catch
Validate before calling
doc = Nokogiri::XML(body)
doc.at_xpath('//FlexQueryResponse').present? && doc.xpath('//FlexStatement').any? # both must hold before parse Try / catch
rescue IbkrItem::ReportParser::ParseError; the 'no FlexStatement nodes' variant is a configuration/timing issue — verify the Flex Query definition and retry later rather than treating the payload as corrupt
Prevention
- Confirm the Flex Query includes statement-producing sections for the target date range
- Expect empty reports during new-token activation; schedule a delayed retry
- Distinguish empty-statement from malformed-XML failures in sync telemetry
When it happens
Trigger: A Flex report with no FlexStatement elements: a Flex Query configured with no statement-producing sections for the requested date range, or a minimal ack document from IBKR.
Common situations: Newly created Flex Queries with no data yet; query date ranges excluding all statements; IBKR occasionally returning empty reports while a new token is still activating (data lag).
Related errors
- Invalid IBKR Flex XML: missing FlexQueryResponse root.
- Invalid IBKR Flex XML: missing account identifier in FlexSta
- IBKR Flex did not return a reference code.
- Invalid IBKR Flex XML: #{e.message}
- query_id is required
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/9972b792aa06b3da.
Report an issue: GitHub.