{"record":{"id":"25e4cf8f1952bfce","repo":"bblimke/webmock","slug":"invalid-json-string-yaml-error-e-inspect","errorCode":null,"errorMessage":"Invalid JSON string: #{yaml}, Error: #{e.inspect}","messagePattern":"Invalid JSON string: #(.+?), Error: #(.+?)","errorType":"exception","errorClass":"WebMock::Util::Parsers::ParseError","httpStatus":null,"severity":"error","filePath":"lib/webmock/util/parsers/json.rb","lineNumber":20,"sourceCode":"\n# This is a copy of https://github.com/jnunemaker/crack/blob/master/lib/crack/json.rb\n# with date parsing removed\n# Copyright (c) 2004-2008 David Heinemeier Hansson\n# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nrequire_relative \"parse_error\"\n\nmodule WebMock\n  module Util\n    module Parsers\n      class JSON\n        def self.parse(json)\n          yaml = unescape(convert_json_to_yaml(json))\n          YAML.load(yaml)\n        rescue ArgumentError, Psych::SyntaxError => e\n          raise ParseError, \"Invalid JSON string: #{yaml}, Error: #{e.inspect}\"\n        end\n\n        protected\n\n        def self.unescape(str)\n          str.gsub(/\\\\u([0-9a-f]{4})/) { [$1.hex].pack(\"U\") }\n        end\n\n        # Ensure that \":\" and \",\" are always followed by a space\n        def self.convert_json_to_yaml(json) #:nodoc:\n          scanner, quoting, marks, times = StringScanner.new(json), false, [], []\n          while scanner.scan_until(/(\\\\['\"]|['\":,\\\\]|\\\\.)/)\n            case char = scanner[1]\n            when '\"', \"'\"\n              if !quoting\n                quoting = char\n              elsif quoting == char\n                quoting = false","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/bblimke/webmock/blob/b187df8827e1f08a1684a8ddc0a5050dbd449c16/lib/webmock/util/parsers/json.rb#L2-L38","documentation":"WebMock::ParseError raised when WebMock's internal JSON parser (Util::Parsers::JSON, which converts JSON to YAML and calls YAML.load) cannot parse a body during request/stub body normalization. It fires when either the stub body pattern or the real request body is unparseable; the message echoes the offending string plus the underlying ArgumentError or Psych::SyntaxError. Because parsing routes through YAML, even valid JSON can fail when YAML misreads a scalar (classic case: unquoted date-like strings).","triggerScenarios":"stub_request(:post, url).with(body: {...}, headers: { 'Content-Type' => 'application/json' }) where either side contains invalid JSON: trailing commas, single-quoted strings, unquoted keys, NaN/Infinity; a JSON string body pattern like .with(body: '{\"a\":1,}'); YAML date-coercion failures on values such as 2026-08-22 under psych versions that turn them into Date objects; strings Psych rejects after the json-to-yaml conversion.","commonSituations":"Hand-written JSON fixtures with trailing commas; payloads assembled by string interpolation instead of a JSON serializer; Ruby or psych upgrades making YAML.load stricter or changing date coercion; non-UTF-8 bytes or a BOM in the body; tests that stub with a Hash while the client sends malformed JSON.","solutions":["Copy the body shown in the error message and run it through WebMock::Util::JSON.parse or JSON.parse in a console to see the exact cause","Fix the malformed JSON: remove trailing commas, double-quote keys and strings, drop JavaScript-only literals (NaN, undefined, single quotes)","If YAML scalar coercion is the culprit, match the raw body string instead of a parsed hash: .with(body: '{\"d\":\"2026-08-22\"}')","For exotic bodies use a block matcher: .with(headers: { 'Content-Type' => 'application/json' }) { |req| JSON.parse(req.body)['d'] == '2026-08-22' }","Upgrade webmock; parser edge cases (dates, unicode) keep getting fixed across releases"],"exampleFix":"// before\nstub_request(:post, 'www.example.com')\n  .with(body: { 'd' => '2026-08-22' }, headers: { 'Content-Type' => 'application/json' })\n# date-like scalar can break the YAML-backed parser on some psych versions\n\n// after - match the raw JSON string exactly\nstub_request(:post, 'www.example.com')\n  .with(body: '{\"d\":\"2026-08-22\"}', headers: { 'Content-Type' => 'application/json' })","handlingStrategy":"validation","validationCode":"require 'json'\n\ndef valid_json_body?(body)\n  JSON.parse(body)\n  true\nrescue JSON::ParserError\n  false\nend\n\nbody = client.build_payload\nraise ArgumentError, 'client produced invalid JSON' unless valid_json_body?(body)\nHTTP.post(url, body: body, headers: { 'Content-Type' => 'application/json' })","typeGuard":"def stubbable_json_pattern?(pattern)\n  return true unless pattern.is_a?(String)\n  return true unless pattern.strip.start_with?('{', '[')\n  valid_json_body?(pattern)\nend","tryCatchPattern":"begin\n  WebMock::Util::JSON.parse(body)\nrescue WebMock::ParseError => e\n  # e.message shows the converted YAML plus the Psych/ArgumentError cause;\n  # fix the payload or fixture - do not swallow this in tests\nend","preventionTips":["Always build request bodies with JSON.generate / JSON.dump instead of string interpolation","Run fixtures through JSON.parse once at load time so bad fixtures fail before stubbing","Prefer exact string body matching for payloads with date-like or bare scalar values","Re-check pinned psych/webmock versions after Ruby upgrades"],"tags":["webmock","ruby","json","parseerror","psych","yaml","body-matching"],"backgroundTag":"invalid-json-body","analyzedSha":"b187df8827e1f08a1684a8ddc0a5050dbd449c16","analyzedAt":"2026-08-23T02:55:22.028Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}