bblimke/webmock · error · WebMock::Util::Parsers::ParseError
Invalid XML string: #{xml}, Error: #{e.inspect}
Error message
Invalid XML string: #{xml}, Error: #{e.inspect} What it means
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.
Source
Thrown at lib/webmock/util/parsers/xml.rb:11
require_relative "parse_error"
require "crack/xml"
module WebMock
module Util
module Parsers
class XML
def self.parse(xml)
::Crack::XML.parse(xml)
rescue ::REXML::ParseException => e
raise ParseError, "Invalid XML string: #{xml}, Error: #{e.inspect}"
end
end
end
end
end
View on GitHub (pinned to b187df8827)
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 &, 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
Example fix
// before
stub_request(:post, 'www.example.com')
.with(body: '<a>1</a><b>2</b>', headers: { 'Content-Type' => 'application/xml' })
# two root elements -> REXML::ParseException -> WebMock::ParseError
// after
stub_request(:post, 'www.example.com')
.with(body: '<r><a>1</a><b>2</b></r>', headers: { 'Content-Type' => 'application/xml' }) Defensive patterns
Strategy: validation
Validate before calling
require 'rexml/document'
def well_formed_xml?(body)
REXML::Document.new(body)
true
rescue REXML::ParseException
false
end
xml = client.build_xml
raise ArgumentError, 'client produced malformed XML' unless well_formed_xml?(xml)
HTTP.post(url, body: xml, headers: { 'Content-Type' => 'application/xml' }) Try / catch
begin WebMock::Util::XML.parse(body) rescue WebMock::ParseError => e # e.message contains the document and the REXML cause - fix the XML, never rescue-and-ignore in tests end
Prevention
- 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
When it happens
Trigger: 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 , a broken encoding declaration, or is truncated (e.g. a streaming client cut off mid-payload).
Common situations: 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.
Related errors
- Invalid JSON string: #{yaml}, Error: #{e.inspect}
- Real HTTP connections are disabled. Unregistered request: #{
- #with method invoked with no arguments. Either options hash
- The basic_auth option value should be an array which contain
- URI should be a String, Regexp, Addressable::Template, a cal
AI-assisted analysis of bblimke/webmock@b187df8827 (2026-08-23).
Data as JSON: /api/errors/48e7590467d996a3.
Report an issue: GitHub.