{"record":{"id":"48e7590467d996a3","repo":"bblimke/webmock","slug":"invalid-xml-string-xml-error-e-inspect","errorCode":null,"errorMessage":"Invalid XML string: #{xml}, Error: #{e.inspect}","messagePattern":"Invalid XML string: #(.+?), Error: #(.+?)","errorType":"exception","errorClass":"WebMock::Util::Parsers::ParseError","httpStatus":null,"severity":"error","filePath":"lib/webmock/util/parsers/xml.rb","lineNumber":11,"sourceCode":"require_relative \"parse_error\"\nrequire \"crack/xml\"\n\nmodule WebMock\n  module Util\n    module Parsers\n      class XML\n        def self.parse(xml)\n          ::Crack::XML.parse(xml)\n        rescue ::REXML::ParseException => e\n          raise ParseError, \"Invalid XML string: #{xml}, Error: #{e.inspect}\"\n        end\n      end\n    end\n  end\nend\n","sourceCodeStart":1,"sourceCodeEnd":17,"githubUrl":"https://github.com/bblimke/webmock/blob/b187df8827e1f08a1684a8ddc0a5050dbd449c16/lib/webmock/util/parsers/xml.rb#L1-L17","documentation":"WebMock::ParseError raised when Crack::XML cannot parse an XML request body during body normalization for matching; the underlying REXML::ParseException is wrapped. It fires when a stub declares an XML body pattern (Hash or String) and either that pattern or the incoming request body is not well-formed XML. The message echoes the offending document and the parser cause.","triggerScenarios":"stub_request(:post, url).with(body: xml_or_hash, headers: { 'Content-Type' => 'application/xml' }) where the XML has unclosed tags, more than one root element, undefined entities like &nbsp;, a broken encoding declaration, or is truncated (e.g. a streaming client cut off mid-payload).","commonSituations":"Fixtures containing HTML entities that are undefined in XML; XML assembled by concatenating fragments; HTML sent with an XML content type; encodings declared in the prolog that disagree with the actual bytes; clients that truncate bodies on timeout.","solutions":["Parse the document shown in the error with REXML::Document or Nokogiri to get the exact line/column of the break","Fix well-formedness: one root element, all tags closed, ampersands escaped as &amp;, prolog matching the actual encoding","Replace undefined HTML entities or supply the DOCTYPE that defines them","Match the body as an exact String instead of a parsed XML Hash when byte-exact matching is acceptable"],"exampleFix":"// before\nstub_request(:post, 'www.example.com')\n  .with(body: '<a>1</a><b>2</b>', headers: { 'Content-Type' => 'application/xml' })\n# two root elements -> REXML::ParseException -> WebMock::ParseError\n\n// after\nstub_request(:post, 'www.example.com')\n  .with(body: '<r><a>1</a><b>2</b></r>', headers: { 'Content-Type' => 'application/xml' })","handlingStrategy":"validation","validationCode":"require 'rexml/document'\n\ndef well_formed_xml?(body)\n  REXML::Document.new(body)\n  true\nrescue REXML::ParseException\n  false\nend\n\nxml = client.build_xml\nraise ArgumentError, 'client produced malformed XML' unless well_formed_xml?(xml)\nHTTP.post(url, body: xml, headers: { 'Content-Type' => 'application/xml' })","typeGuard":null,"tryCatchPattern":"begin\n  WebMock::Util::XML.parse(body)\nrescue WebMock::ParseError => e\n  # e.message contains the document and the REXML cause - fix the XML, never rescue-and-ignore in tests\nend","preventionTips":["Generate XML with a builder (Nokogiri::XML::Builder, REXML) rather than concatenation","Escape ampersands and use only the five predefined XML entities in fixtures","Validate third-party XML fixtures once at load time","Keep Content-Type honest - do not label HTML as application/xml"],"tags":["webmock","ruby","xml","rexml","crack","parseerror"],"backgroundTag":"invalid-xml-body","analyzedSha":"b187df8827e1f08a1684a8ddc0a5050dbd449c16","analyzedAt":"2026-08-23T02:55:22.028Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}