{"record":{"id":"474efe11138ac570","repo":"we-promise/sure","slug":"ibkr-flex-did-not-return-a-reference-code","errorCode":null,"errorMessage":"IBKR Flex did not return a reference code.","messagePattern":"IBKR Flex did not return a reference code\\.","errorType":"exception","errorClass":"ApiError","httpStatus":null,"severity":"error","filePath":"app/models/provider/ibkr_flex.rb","lineNumber":67,"sourceCode":"\n  def download_statement\n    reference_code = request_reference_code\n    poll_statement(reference_code)\n  end\n\n  private\n\n    def request_reference_code\n      response = with_retries(\"SendRequest\") do\n        self.class.get(\"/SendRequest\", query: { t: token, q: query_id, v: 3 })\n      end\n\n      xml = parse_xml(response.body)\n      error = response_error(xml, response)\n      raise error if error\n\n      reference_code = xml.at_xpath(\"//ReferenceCode\")&.text.to_s.strip\n      raise ApiError.new(\"IBKR Flex did not return a reference code.\", status_code: response.code, response_body: response.body) if reference_code.blank?\n\n      reference_code\n    end\n\n    def poll_statement(reference_code)\n      attempts = 0\n\n      loop do\n        attempts += 1\n        response = with_retries(\"GetStatement\") do\n          self.class.get(\"/GetStatement\", query: { t: token, q: reference_code, v: 3 })\n        end\n\n        xml = parse_xml(response.body)\n        return response.body if xml.at_xpath(\"//FlexQueryResponse\")\n\n        error = response_error(xml, response)\n        if error.is_a?(ApiError) && PENDING_ERROR_CODES.include?(error.error_code.to_s)","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/ibkr_flex.rb#L49-L85","documentation":"GET /SendRequest?t=token&q=query_id&v=3 succeeded at the transport level and returned XML with neither //ErrorCode (any ErrorCode would have been raised earlier by response_error) nor a usable //ReferenceCode. The expected contract is SendRequest returning a ReferenceCode that GetStatement later polls; a blank one means IBKR answered with an unexpected-but-non-error body.","triggerScenarios":"The token/query_id pair passes basic validation but the Flex Query itself is empty or disabled (no data sections selected), so IBKR returns a stub body; a response envelope change drops or renames ReferenceCode; the token was regenerated and the old query association returns an inert response.","commonSituations":"Copy-pasting the Flex Query *name* instead of its numeric ID (or vice versa), creating a Flex Query in Client Portal without enabling any report sections, regenerating the Flex token but keeping a stale query ID, IBKR quietly changing the SendRequest response shape.","solutions":["Verify both values in IBKR Client Portal (Performance & Reports > Flex Queries > Flex Web Service): the token and the numeric query ID of a query with at least one data section enabled","Reproduce manually: curl \"https://ndcdyn.interactivebrokers.com/AccountManagement/FlexWebService/SendRequest?t=<token>&q=<query>&v=3\" and inspect the XML","Inspect e.response_body on the raised ApiError - it carries the exact XML that lacked the ReferenceCode","Regenerate the Flex token, wait a few minutes for propagation, and retry"],"exampleFix":"# before\ndef download\n  Provider::IbkrFlex.new(query_id: qid, token: tok).download_statement\nend\n\n# after\ndef download\n  Provider::IbkrFlex.new(query_id: qid, token: tok).download_statement\nrescue Provider::IbkrFlex::ApiError => e\n  Rails.logger.error(\"SendRequest body without ReferenceCode: #{e.response_body}\")\n  raise\nend","handlingStrategy":"try-catch","validationCode":"# IBKR Flex query IDs are numeric; tokens are long alphanumeric strings\nfail \"query_id must be numeric\" unless query_id.to_s.match?(/\\A\\d+\\z/)\nfail \"token looks wrong (expect 30+ chars)\" unless token.to_s.length >= 30\nflex = Provider::IbkrFlex.new(query_id: query_id, token: token)","typeGuard":"def ibkr_missing_reference_code?(error)\n  error.is_a?(Provider::IbkrFlex::ApiError) &&\n    error.message.include?(\"did not return a reference code\")\nend","tryCatchPattern":"begin\n  flex.download_statement\nrescue Provider::IbkrFlex::ApiError => e\n  if e.message.include?(\"did not return a reference code\")\n    Rails.logger.error(\"SendRequest returned: #{e.response_body}\") # exact XML for diagnosis\n    CredentialAlert.notify(:ibkr_flex, account) # config problem, not transient\n  end\n  raise\nend","preventionTips":["Store query_id and token exactly as shown in Client Portal > Flex Queries, and lint query_id as numeric","Ensure the Flex Query has at least one data section enabled before using it","Add a smoke-test job that runs SendRequest after any credential rotation","Log e.response_body whenever this fires - the XML tells you exactly what IBKR sent"],"tags":["ibkr-flex","sendrequest","reference-code","xml","flex-query"],"backgroundTag":"missing-field-in-api-response","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}