{"record":{"id":"c3775c39faafc44e","repo":"puppetlabs/puppet","slug":"the-request-body-is-invalid-message","errorCode":null,"errorMessage":"The request body is invalid: %{message}","messagePattern":"The request body is invalid: %(.+?)","errorType":"http","errorClass":"Puppet::Network::HTTP::Error::HTTPBadRequestError","httpStatus":400,"severity":"error","filePath":"lib/puppet/network/http/api/indirected_routes.rb","lineNumber":228,"sourceCode":"  def accepted_response_formatters_for(model_class, request)\n    request.response_formatters_for(model_class.supported_formats)\n  end\n\n  # Return the first response formatter that the client accepts and\n  # the server supports, or default to 'application/json'.\n  def accepted_response_formatter_or_json_for(model_class, request)\n    request.response_formatters_for(model_class.supported_formats, \"application/json\").first\n  end\n\n  def read_body_into_model(model_class, request)\n    data = request.body.to_s\n    formatter = request.formatter\n\n    if formatter.supported?(model_class)\n      begin\n        return model_class.convert_from(formatter.name.to_s, data)\n      rescue => e\n        raise Puppet::Network::HTTP::Error::HTTPBadRequestError, _(\"The request body is invalid: %{message}\") % { message: e.message }\n      end\n    end\n\n    # TRANSLATORS \"mime-type\" is a keyword and should not be translated\n    raise Puppet::Network::HTTP::Error::HTTPUnsupportedMediaTypeError.new(\n      _(\"Client sent a mime-type (%{header}) that doesn't correspond to a format we support\") % { header: request.headers['content-type'] },\n      Puppet::Network::HTTP::Issues::UNSUPPORTED_MEDIA_TYPE\n    )\n  end\n\n  def indirection_method(http_method, indirection)\n    raise Puppet::Network::HTTP::Error::HTTPMethodNotAllowedError, _(\"No support for http method %{http_method}\") % { http_method: http_method } unless METHOD_MAP[http_method]\n\n    method = METHOD_MAP[http_method][plurality(indirection)]\n    unless method\n      raise Puppet::Network::HTTP::Error::HTTPBadRequestError, _(\"No support for plurality %{indirection} for %{http_method} operations\") % { indirection: plurality(indirection), http_method: http_method }\n    end\n","sourceCodeStart":210,"sourceCodeEnd":246,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/network/http/api/indirected_routes.rb#L210-L246","documentation":"For PUT/POST requests the handler deserializes the body with model_class.convert_from using the format derived from the Content-Type header. Any exception raised during that conversion is wrapped into HTTP 400 'The request body is invalid: <original message>'. The underlying parser message is preserved, so the actual cause (bad JSON, wrong schema, truncated body) is visible in the response.","triggerScenarios":"PUT /puppet/v3/report/mynode with malformed JSON; submitting facts whose payload does not match the expected model schema; a Content-Type header claiming a format the body is not; truncated bodies from proxy timeouts; agent/server version skew where the payload schema differs.","commonSituations":"Custom report or fact submitters that hand-roll JSON; agent and server versions out of step so new fields are rejected; load balancers or proxies truncating large catalog/report bodies.","solutions":["Capture the exact body sent and validate it locally (JSON.parse or the format's convert_from) to locate the malformed part","Ensure the Content-Type header matches the actual body format (application/json for JSON)","Align agent and server versions, or adjust the payload to the schema the server expects","Check body size limits in intermediate proxies if bodies arrive truncated"],"exampleFix":"# before: submitting invalid JSON\ncurl -X PUT -H 'Content-Type: application/json' \\\n  -d '{ \"name\": \"mynode\", ' \\\n  \"https://puppet:8140/puppet/v3/report/mynode?environment=production\"\n\n# after: valid, complete JSON document sent from a file\ncurl -X PUT -H 'Content-Type: application/json' \\\n  -d @report.json \\\n  \"https://puppet:8140/puppet/v3/report/mynode?environment=production\"","handlingStrategy":"try-catch","validationCode":"require 'json'\n\npayload = report.to_json\nJSON.parse(payload)  # raises now, with our own context, instead of server-side\nclient.put(\"/puppet/v3/report/#{certname}\", body: payload,\n           headers: { 'Content-Type' => 'application/json' },\n           params: { environment: env })","typeGuard":null,"tryCatchPattern":"begin\n  client.put(\"/puppet/v3/report/#{certname}\",\n             body: payload,\n             headers: { 'Content-Type' => 'application/json' },\n             params: { environment: env })\nrescue Puppet::Network::HTTP::Error::HTTPBadRequestError => e\n  # e.message carries the underlying parse error, e.g. 'The request body is invalid: unexpected token'\n  raise \"report rejected for #{certname}: #{e.message}\"\nend","preventionTips":["Round-trip serialized output through the parser (JSON.parse) before sending","Always send an explicit Content-Type matching the body","Keep an integration test that submits the exact payload your tooling produces"],"tags":["http","request-body","deserialization","rest-api"],"backgroundTag":"invalid-request-body","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}