-
Notifications
You must be signed in to change notification settings - Fork 7
Description
Component
- API Server / GraphQL
Infrahub version
release-1.6
Current Behavior
The ConvertObjectType mutation fails with a Pydantic validation error when the UI sends attribute_value: null in the fields mapping. The validator in ConversionFieldValue treats explicitly set null values as a field being set, causing it to fail the "exactly one field must be set" constraint.
UI Error:
1 validation error for ConversionFieldInput data Value error, Exactly one of `attribute_value`, `peer_id`, or `peers_ids` must be set [type=value_error, input_value={'attribute_value': None}, input_type=dict] For further information visit https://errors.pydantic.dev/2.10/v/value_error
Server Stack Trace:
Traceback (most recent call last):
File "/.venv/lib/python3.12/site-packages/graphql/execution/execute.py", line 530, in await_result
return_type, field_nodes, info, path, await result
^^^^^^^^^^^^
File "/source/backend/infrahub/graphql/mutations/convert_object_type.py", line 59, in mutate
fields_mapping[field_name] = ConversionFieldInput(**input_for_dest_field_str)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/.venv/lib/python3.12/site-packages/pydantic/main.py", line 214, in __init__
validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pydantic_core._pydantic_core.ValidationError: 1 validation error for ConversionFieldInput
data
Value error, Exactly one of `attribute_value`, `peer_id`, or `peers_ids` must be set [type=value_error, input_value={'attribute_value': None}, input_type=dict]
For further information visit https://errors.pydantic.dev/2.10/v/value_errorExpected Behavior
The mutation should handle null values gracefully, treating them as unset fields rather than explicitly set fields. The conversion should complete successfully.
Steps to Reproduce
- Use the convert-type feature in the UI
- Convert an object with fields that need to be set to null/empty values
- Execute the ConvertObjectType mutation with a fieldsMapping containing entries like:
"city": { "data": { "attribute_value": null } }
- Observe the validation error
Full mutation example:
mutation (
$nodeId: String!
$targetKind: String!
$fieldsMapping: GenericScalar!
) {
ConvertObjectType(
data: {
node_id: $nodeId
target_kind: $targetKind
fields_mapping: $fieldsMapping
}
) {
node
__typename
}
}Variables:
{
"nodeId": "187c27f6-7eef-186a-3665-c51903599ca0",
"targetKind": "LocationSite",
"fieldsMapping": {
"city": {
"data": {
"attribute_value": null
}
},
"name": {
"source_field": "name"
},
"address": {
"data": {
"attribute_value": null
}
},
"description": {
"source_field": "description"
},
"contact": {
"data": {
"attribute_value": null
}
},
"tags": {
"use_default_value": true
},
"parent": {
"data": {
"peer_id": {
"id": "187c22c9-80c3-d620-3663-c510a9105307",
"display_label": "Mexico",
"__typename": "LocationCountry"
}
}
},
"member_of_groups": {
"source_field": "member_of_groups"
}
}
}Additional Information
Root Cause:
The issue is in python_sdk/infrahub_sdk/convert_object_type.py in the ConversionFieldValue class. The Pydantic validator checks if fields are not None, but when the UI sends {"attribute_value": null}, Pydantic sees this as the field being explicitly set (even though it's None), which fails the validation.
@model_validator(mode="after")
def check_only_one_field(self) -> ConversionFieldValue:
fields = [self.attribute_value, self.peer_id, self.peers_ids]
set_fields = [f for f in fields if f is not None]
if len(set_fields) != 1:
raise ValueError("Exactly one of `attribute_value`, `peer_id`, or `peers_ids` must be set")
return selfSuggested Fix:
The validator should check which fields were explicitly provided in the input, not just which are non-None. This can be done using Pydantic's model_fields_set attribute:
@model_validator(mode="after")
def check_only_one_field(self) -> ConversionFieldValue:
if len(self.model_fields_set) != 1:
raise ValueError("Exactly one of `attribute_value`, `peer_id`, or `peers_ids` must be set")
return selfAlternatively, the UI could be updated to not send fields with null values, or to use use_default_value: true instead of data: {attribute_value: null} when the user wants to set an attribute to null/empty.
Environment:
- Python: 3.12
- Pydantic: 2.10