Skip to content

bug: ConvertObjectType mutation fails with validation error when UI sends null attribute_value #667

@BeArchiTek

Description

@BeArchiTek

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_error

Expected 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

  1. Use the convert-type feature in the UI
  2. Convert an object with fields that need to be set to null/empty values
  3. Execute the ConvertObjectType mutation with a fieldsMapping containing entries like:
    "city": {
      "data": {
        "attribute_value": null
      }
    }
  4. 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 self

Suggested 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 self

Alternatively, 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

Metadata

Metadata

Assignees

Labels

state/need-triageThis issue needs to be triagedtype/bugSomething isn't working as expected

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions