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

  1. Verify the Flex Query (query_id) in IBKR Portal includes the statement types and date range you expect
  2. Retry later — Flex report data can lag behind token/query creation
  3. 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

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


AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21). Data as JSON: /api/errors/9972b792aa06b3da. Report an issue: GitHub.