symfony/http-kernel · error · BadRequestHttpException

Request payload contains invalid

Error message

Request payload contains invalid "%s" data.

What it means

During #[MapRequestPayload] deserialization, a NotEncodableValueException means the request body could not be decoded into a PHP structure in the request's format - typically malformed JSON/XML. Symfony rethrows it as a 400 BadRequestHttpException with the format named in the message. It tells the client their payload is syntactically invalid.

Solutions

  1. Validate the client payload with a JSON linter/JSON.parse before sending.
  2. Ensure Content-Type matches the actual body format (don't send XML with application/json).
  3. Check for body truncation: raise proxy/web-server body limits or reduce payload size.
  4. Serialize with a real JSON library rather than string concatenation.

Example fix

// before: invalid JSON with trailing comma
'{"name":"John",}'
// after
'{"name":"John"}'
Defensive patterns

Strategy: validation

Validate before calling

const body = buildPayload();
JSON.parse(body); // throws SyntaxError before sending if malformed
fetch(url, { method: 'POST', headers: {'Content-Type': 'application/json'}, body });

Try / catch

try {
    $result = $api->submit($payload);
} catch (BadRequestHttpException $e) {
    $logger->error('Payload rejected as malformed', ['previous' => $e->getPrevious()?->getMessage()]);
    // fix and resend the payload
}

Prevention

When it happens

Trigger: Sending invalid JSON (trailing commas, unquoted keys, truncated body, wrong encoding) with Content-Type: application/json to a controller using #[MapRequestPayload]; malformed XML for xml Content-Type; empty body where one is required.

Common situations: Hand-rolled clients concatenating JSON strings; broken template interpolation producing invalid JSON; request bodies cut off by proxies or body size limits; BOM or charset issues in the payload.

Related errors


AI-assisted analysis of symfony/http-kernel@aa3a39d728 (2026-09-13). Data as JSON: /api/errors/45295a30bc824dfa. Report an issue: GitHub.

Appendix: source

Thrown at Controller/ArgumentResolver/RequestPayloadValueResolver.php:288

            default => $argument->getType(),
        };

        if (\is_array($data)) {
            $data = $this->mergeParamsAndFiles($data, $request->files->all());

            return $this->serializer->denormalize($data, $type, self::hasNonStringScalar($data) ? $format : 'csv', $attribute->serializationContext + self::CONTEXT_DENORMALIZE + ('form' === $format ? ['filter_bool' => true] : []));
        }

        if ('form' === $format) {
            throw new BadRequestHttpException('Request payload contains invalid "form" data.');
        }

        try {
            return $this->serializer->deserialize($data, $type, $format, self::CONTEXT_DESERIALIZE + $attribute->serializationContext);
        } catch (UnsupportedFormatException $e) {
            throw new UnsupportedMediaTypeHttpException(\sprintf('Unsupported format: "%s".', $format), $e);
        } catch (NotEncodableValueException $e) {
            throw new BadRequestHttpException(\sprintf('Request payload contains invalid "%s" data.', $format), $e);
        } catch (UnexpectedPropertyException $e) {
            throw new BadRequestHttpException(\sprintf('Request payload contains invalid "%s" property.', $e->property), $e);
        }
    }

    private function mapUploadedFile(Request $request, ArgumentMetadata $argument, MapUploadedFile $attribute): UploadedFile|array|null
    {
        if ($files = $request->files->get($attribute->name ?? $argument->getName())) {
            return !\is_array($files) && $argument->isVariadic() ? [$files] : $files;
        }

        if ($argument->isNullable() || $argument->hasDefaultValue()) {
            return null;
        }

        return 'array' === $argument->getType() ? [] : null;
    }

View on GitHub (pinned to aa3a39d728)