symfony/http-kernel · error · BadRequestHttpException
Request payload contains invalid
Error message
Request payload contains invalid "%s" property.
What it means
When deserializing a request payload mapped via #[MapRequestPayload], the serializer encountered an UnexpectedPropertyException - the JSON/body contains a property that does not exist on the target DTO and strict property handling is active. Symfony converts it to a 400 with the offending property name. This guards typed DTOs against unexpected/misspelled fields.
Solutions
- Remove the unknown property from the client payload or fix its spelling to match the DTO.
- Add the missing property to the DTO (or a #[SerializedName]) if the field is legitimate.
- Set serializationContext on the attribute: ['allow_extra_attributes' => true] to ignore extra fields.
- Version your API so old clients keep sending payloads compatible with the deployed DTO.
Example fix
// before #[MapRequestPayload] UserDto $dto // after: tolerate extra fields #[MapRequestPayload(serializationContext: ['allow_extra_attributes' => true])] UserDto $dto
Defensive patterns
Strategy: type-guard
Validate before calling
const allowed = new Set(['name','email']);
const extra = Object.keys(payload).filter(k => !allowed.has(k));
if (extra.length) throw new Error('Unknown fields: ' + extra.join(',')); Try / catch
try {
$result = $api->submit($payload);
} catch (BadRequestHttpException $e) {
// message names the offending property; strip it and retry
$logger->warning('Unexpected property sent', ['msg' => $e->getMessage()]);
} Prevention
- Keep client payloads in sync with DTO definitions; generate clients from OpenAPI/schema.
- Fix field-name typos immediately after any DTO rename.
- Use serializationContext allow_extra_attributes when forward compatibility matters.
When it happens
Trigger: Client sends JSON with a key that has no matching property on the mapped DTO class while the serializer context enables strict/ignore-false behavior (e.g. denormalize with 'allow_extra_attributes' => false or default strict behavior in recent serializer versions).
Common situations: API clients sending extra metadata fields; renamed DTO properties after an upgrade while clients still send old field names; typos in field names; Symfony 7.x stricter serializer defaults.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Request payload contains invalid "form" data.
- Unsupported format: " ".
- Request payload contains invalid
- The uid for the " " parameter is invalid.
- The "symfony/serializer" component is required to use the "#
AI-assisted analysis of symfony/http-kernel@aa3a39d728 (2026-09-13).
Data as JSON: /api/errors/eda386649aea3519.
Report an issue: GitHub.
Appendix: source
Thrown at Controller/ArgumentResolver/RequestPayloadValueResolver.php:290
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;
}
private function mergeParamsAndFiles(array $params, array $files): array
{View on GitHub (pinned to aa3a39d728)