diff --git a/Documentation/release/dev/add-state_metadata_vtk_fields-vtkConduitSource.md b/Documentation/release/dev/add-state_metadata_vtk_fields-vtkConduitSource.md
new file mode 100644
index 0000000000000000000000000000000000000000..ba2977485ee569bf492a1602e7b60d223c6eb609
--- /dev/null
+++ b/Documentation/release/dev/add-state_metadata_vtk_fields-vtkConduitSource.md
@@ -0,0 +1,61 @@
+## vtkConduitSource: Add state/metadata/vtk_fields node
+
+When defining fields in a Conduit tree, it is often useful to include metadata about the fields that can be
+interpreted by VTK, and utilized appropriately. To that end, we have added a new node to the Conduit tree
+that can be used to store metadata about the fields in the tree. This node is called `state/metadata/vtk_fields`.
+
+Each child of the `state/metadata/vtk_fields` node has a name that corresponds to a field in the tree. The number
+of children of the `state/metadata/vtk_fields` node should not match the number of `fields` in the tree since not every
+field needs to have metadata.
+
+The current metadata that can be stored for each field is:
+
+1. `attribute_type`: It is a string and represents the attribute type of a field that, so that VTk can use an attribute
+   array, such as `GlobalIds`. The values uses are the entries of `vtkDataSetAttributes::AttributeTypes` + `Ghosts`.
+   The complete list of values is:
+   - `Scalars`
+   - `Vectors`
+   - `Normals`
+   - `TCoords`
+   - `Tensors`
+   - `GlobalIds`
+   - `PedigreeIds`
+   - `EdgeFlag`
+   - `Tangents`
+   - `RationalWeights`
+   - `HigherOrderDegrees`
+   - `ProcessIds`
+   - `Ghosts`
+2. `values_to_replace` and `replacement_values`: These two are vectors of values that be used to replace specific values
+   in the field. This is useful when the field has some values that are not valid for VTK. For example,
+   the `vtkGhostType` array uses specific values that other ghost cell generator algorithms may not use. In this case,
+   the `values_to_replace` would be the values that need to be replaced, and the `replacement_values` would be the
+   values that should replace them. The two vectors should have the same length.
+
+Example:
+
+```cpp
+conduit_cpp::Node mesh;
+CreateUniformMesh(3, 3, 3, mesh);
+
+std::vector<int> cellGhosts(8, 0);
+cellGhosts[2] = 1;
+
+conduit_cpp::Node resCellFields = mesh["fields/other_ghosts"];
+resCellFields["association"] = "element";
+resCellFields["topology"] = "mesh";
+resCellFields["volume_dependent"] = "false";
+resCellFields["values"] = cellGhosts;
+
+std::vector<int> cellGhostValuesToReplace(1, 1);
+std::vector<int> cellGhostReplacementValues(1, vtkDataSetAttributes::HIDDENCELL);
+
+std::vector<int> cellGhostsMetaData(1, 1);
+conduit_cpp::Node ghostMetaData = mesh["state/metadata/vtk_fields/other_ghosts"];
+ghostMetaData["attribute_type"] = "Ghosts";
+ghostMetaData["values_to_replace"] = cellGhostValuesToReplace;
+ghostMetaData["replacement_values"] = cellGhostReplacementValues;
+```
+
+Lastly, the usage of `ascent_ghosts` has been deprecated and should be replaced with the new
+`state/metadata/vtk_fields` node, as shown above.
diff --git a/IO/CatalystConduit/Testing/Cxx/TestConduitSource.cxx b/IO/CatalystConduit/Testing/Cxx/TestConduitSource.cxx
index 3468b5fd1dce8b979f8118283dc0913840f79063..a21ed91a2b7d9e50a44d93e4b51d18b1376adde3 100644
--- a/IO/CatalystConduit/Testing/Cxx/TestConduitSource.cxx
+++ b/IO/CatalystConduit/Testing/Cxx/TestConduitSource.cxx
@@ -412,6 +412,10 @@ void CreateTrisMesh(unsigned int nptsX, unsigned int nptsY, conduit_cpp::Node& r
     values[i] = i + 0.0;
   }
   resFields["values"].set(values);
+
+  conduit_cpp::Node resFieldsMetaData = res["state/metadata/vtk_fields/field"];
+  resFieldsMetaData["attribute_type"] =
+    vtkDataSetAttributes::GetAttributeTypeAsString(vtkDataSetAttributes::SCALARS);
 }
 
 //----------------------------------------------------------------------------
@@ -434,7 +438,9 @@ bool ValidateMeshTypeUnstructured()
     ug->GetNumberOfPoints());
   VERIFY(ug->GetNumberOfCells() == 8, "incorrect number of cells, expected 8, got %lld",
     ug->GetNumberOfCells());
-  VERIFY(ug->GetCellData()->GetArray("field") != nullptr, "missing 'field' cell-data array");
+  VERIFY(ug->GetCellData()->GetAttribute(vtkDataSetAttributes::SCALARS) != nullptr,
+    "missing 'field' cell-data array with attribute '%s'",
+    vtkDataSetAttributes::GetAttributeTypeAsString(vtkDataSetAttributes::SCALARS));
   return true;
 }
 
@@ -626,14 +632,22 @@ bool ValidateAscentGhostCellData()
   resCellFields["volume_dependent"] = "false";
   resCellFields["values"] = cellGhosts;
 
+  std::vector<int> cellGhostValuesToReplace(1, 1);
+  std::vector<int> cellGhostReplacementValues(1, vtkDataSetAttributes::HIDDENCELL);
+
+  std::vector<int> cellGhostsMetaData(1, 1);
+  conduit_cpp::Node ghostMetaData = mesh["state/metadata/vtk_fields/ascent_ghosts"];
+  ghostMetaData["attribute_type"] = "Ghosts";
+  ghostMetaData["values_to_replace"] = cellGhostValuesToReplace;
+  ghostMetaData["replacement_values"] = cellGhostReplacementValues;
+
   auto data = Convert(mesh);
   auto pds = vtkPartitionedDataSet::SafeDownCast(data);
   VERIFY(pds->GetNumberOfPartitions() == 1, "incorrect number of partitions, expected 1, got %d",
     pds->GetNumberOfPartitions());
   auto img = vtkImageData::SafeDownCast(pds->GetPartition(0));
   VERIFY(img != nullptr, "missing partition 0");
-  vtkUnsignedCharArray* array = vtkUnsignedCharArray::SafeDownCast(
-    img->GetCellData()->GetArray(vtkDataSetAttributes::GhostArrayName()));
+  auto array = vtkUnsignedCharArray::SafeDownCast(img->GetCellData()->GetGhostArray());
   VERIFY(array != nullptr &&
       array->GetValue(2) == static_cast<unsigned char>(vtkDataSetAttributes::HIDDENCELL),
     "Verification failed for converting Ascent ghost cell data");
@@ -655,14 +669,22 @@ bool ValidateAscentGhostPointData()
   resPointFields["topology"] = "mesh";
   resPointFields["values"] = pointGhosts;
 
+  std::vector<int> pointGhostValuesToReplace(1, 1);
+  std::vector<int> pointGhostReplacementValues(1, vtkDataSetAttributes::HIDDENPOINT);
+
+  std::vector<int> cellGhostsMetaData(1, 1);
+  conduit_cpp::Node ghostMetaData = mesh["state/metadata/vtk_fields/ascent_ghosts"];
+  ghostMetaData["attribute_type"] = "Ghosts";
+  ghostMetaData["values_to_replace"] = pointGhostValuesToReplace;
+  ghostMetaData["replacement_values"] = pointGhostReplacementValues;
+
   auto data = Convert(mesh);
   auto pds = vtkPartitionedDataSet::SafeDownCast(data);
   VERIFY(pds->GetNumberOfPartitions() == 1, "incorrect number of partitions, expected 1, got %d",
     pds->GetNumberOfPartitions());
   auto img = vtkImageData::SafeDownCast(pds->GetPartition(0));
   VERIFY(img != nullptr, "missing partition 0");
-  vtkUnsignedCharArray* array = vtkUnsignedCharArray::SafeDownCast(
-    img->GetPointData()->GetArray(vtkDataSetAttributes::GhostArrayName()));
+  auto array = vtkUnsignedCharArray::SafeDownCast(img->GetPointData()->GetGhostArray());
   VERIFY(array != nullptr &&
       array->GetValue(2) == static_cast<unsigned char>(vtkDataSetAttributes::HIDDENPOINT),
     "Verification failed for converting Ascent ghost point data");
diff --git a/IO/CatalystConduit/Testing/Cxx/TestDataObjectToConduit.cxx b/IO/CatalystConduit/Testing/Cxx/TestDataObjectToConduit.cxx
index 53917a9cde9ebf8b93abb2b9d3599993e1949c6b..e346b93e6b2a0086a327049911e7b75ff416c908 100644
--- a/IO/CatalystConduit/Testing/Cxx/TestDataObjectToConduit.cxx
+++ b/IO/CatalystConduit/Testing/Cxx/TestDataObjectToConduit.cxx
@@ -56,6 +56,12 @@ bool TestImageData()
       }
     }
   }
+  vtkNew<vtkUnsignedCharArray> ghostCells;
+  ghostCells->SetName(vtkDataSetAttributes::GhostArrayName());
+  ghostCells->SetNumberOfValues(image->GetNumberOfCells());
+  ghostCells->SetValue(0, 0);
+  ghostCells->SetValue(1, vtkDataSetAttributes::HIDDENCELL);
+  image->GetCellData()->AddArray(ghostCells);
 
   bool is_success =
     vtkDataObjectToConduit::FillConduitNode(vtkDataObject::SafeDownCast(image), node);
@@ -89,6 +95,18 @@ bool TestImageData()
   field_node["volume_dependent"] = "false";
   field_node["values"] = std::vector<int>{ 2, 2, 2, 2, 2, 2 };
 
+  auto field_metadata_node = expected_node["state/metadata/vtk_fields/ImageScalars"];
+  field_metadata_node["attribute_type"] = "Scalars";
+
+  auto ghost_field_node = expected_node["fields/vtkGhostType"];
+  ghost_field_node["association"] = "element";
+  ghost_field_node["topology"] = "mesh";
+  ghost_field_node["volume_dependent"] = "false";
+  ghost_field_node["values"] = std::vector<unsigned char>{ 0, vtkDataSetAttributes::HIDDENCELL };
+
+  auto ghost_field_metadata_node = expected_node["state/metadata/vtk_fields/vtkGhostType"];
+  ghost_field_metadata_node["attribute_type"] = "Ghosts";
+
   conduit_cpp::Node diff_info;
   bool are_nodes_different = node.diff(expected_node, diff_info, 1e-6);
   if (are_nodes_different)
@@ -252,12 +270,18 @@ bool TestStructuredGrid()
   point_field_node["volume_dependent"] = "false";
   point_field_node["values"] = std::vector<double>{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
 
+  auto point_field_metadata_node = expected_node["state/metadata/vtk_fields/point_field"];
+  point_field_metadata_node["attribute_type"] = "Scalars";
+
   auto cell_field_node = expected_node["fields/cell_field"];
   cell_field_node["association"] = "element";
   cell_field_node["topology"] = "mesh";
   cell_field_node["volume_dependent"] = "false";
   cell_field_node["values"] = std::vector<double>{ 0, 2 };
 
+  auto cell_field_metadata_node = expected_node["state/metadata/vtk_fields/cell_field"];
+  cell_field_metadata_node["attribute_type"] = "Scalars";
+
   conduit_cpp::Node diff_info;
   bool are_nodes_different = node.diff(expected_node, diff_info, 1e-6);
   if (are_nodes_different)
diff --git a/IO/CatalystConduit/vtkConduitArrayUtilities.h b/IO/CatalystConduit/vtkConduitArrayUtilities.h
index 4a05b04e3723025e4d10a25ed176a94d3c8acaa8..0e7b77b0aab0350a2b8abefe9cf148612bbca6f7 100644
--- a/IO/CatalystConduit/vtkConduitArrayUtilities.h
+++ b/IO/CatalystConduit/vtkConduitArrayUtilities.h
@@ -17,6 +17,7 @@
 #ifndef vtkConduitArrayUtilities_h
 #define vtkConduitArrayUtilities_h
 
+#include "vtkDeprecation.h"             // for VTK_DEPRECATED_IN_9_5_0
 #include "vtkIOCatalystConduitModule.h" // for exports
 #include "vtkObject.h"
 #include "vtkSmartPointer.h" // for vtkSmartPointer
@@ -51,7 +52,13 @@ public:
   /**
    * Returns a vtkDataArray from a conduit node in the conduit mcarray protocol
    * that is a conduit ghost array named ascent_ghosts.
+   *
+   * @deprecated: Instead of using this function, use the state/metadata/vtk_fields
+   * to define the attribute_type, values_to_replace and replacement_values instead for
+   * the ghost array.
    */
+  VTK_DEPRECATED_IN_9_5_0("This function is deprecated, because in the future "
+                          "state/metadata/vtk_fields will only be used.")
   static vtkSmartPointer<vtkDataArray> MCGhostArrayToVTKGhostArray(
     const conduit_node* mcarray, bool is_cell_data);
   ///@}
diff --git a/IO/CatalystConduit/vtkConduitSource.cxx b/IO/CatalystConduit/vtkConduitSource.cxx
index b5ed87ac31d2ab308310b20875a139aa9e50e132..0359db93a72db2602f8a2876d5309ff1a79f4a4c 100644
--- a/IO/CatalystConduit/vtkConduitSource.cxx
+++ b/IO/CatalystConduit/vtkConduitSource.cxx
@@ -116,7 +116,7 @@ bool vtkConduitSource::GenerateAMR(vtkDataObject* output)
 bool vtkConduitSource::GeneratePartitionedDataSet(vtkDataObject* output)
 {
   vtkNew<vtkPartitionedDataSet> pd_output;
-  if (!vtkConduitToDataObject::FillPartionedDataSet(pd_output, this->Internals->Node))
+  if (!vtkConduitToDataObject::FillPartitionedDataSet(pd_output, this->Internals->Node))
   {
     vtkLogF(ERROR, "Failed reading mesh from '%s'", this->Internals->Node.name().c_str());
     output->Initialize();
@@ -141,7 +141,7 @@ bool vtkConduitSource::GeneratePartitionedDataSetCollection(vtkDataObject* outpu
     const auto& child = pdc_node.child(cc);
     auto pd = pdc_output->GetPartitionedDataSet(static_cast<unsigned int>(cc));
     assert(pd != nullptr);
-    if (!vtkConduitToDataObject::FillPartionedDataSet(pd, child))
+    if (!vtkConduitToDataObject::FillPartitionedDataSet(pd, child))
     {
       vtkLogF(ERROR, "Failed reading mesh '%s'", child.name().c_str());
       output->Initialize();
diff --git a/IO/CatalystConduit/vtkConduitToDataObject.cxx b/IO/CatalystConduit/vtkConduitToDataObject.cxx
index 783960686547087556f4c834f85f6cb1b940574e..30c55483cb65e041514730838865ea8ee34eb785 100644
--- a/IO/CatalystConduit/vtkConduitToDataObject.cxx
+++ b/IO/CatalystConduit/vtkConduitToDataObject.cxx
@@ -1,5 +1,9 @@
 // SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
 // SPDX-License-Identifier: BSD-3-Clause
+
+// Added due to deprecated vtkConduitArrayUtilities::MCGhostArrayToVTKGhostArray
+#define VTK_DEPRECATION_LEVEL 0
+
 #include "vtkConduitToDataObject.h"
 
 #include "vtkAMRBox.h"
@@ -18,11 +22,14 @@
 #include "vtkParallelAMRUtilities.h"
 #include "vtkPartitionedDataSet.h"
 #include "vtkRectilinearGrid.h"
+#include "vtkSMPTools.h"
 #include "vtkStringArray.h"
 #include "vtkStructuredGrid.h"
 #include "vtkUniformGrid.h"
 #include "vtkUnstructuredGrid.h"
 
+#include "vtksys/SystemTools.hxx"
+
 #include <catalyst_conduit.hpp>
 #include <catalyst_conduit_blueprint.hpp>
 
@@ -34,7 +41,64 @@ namespace vtkConduitToDataObject
 VTK_ABI_NAMESPACE_BEGIN
 
 //----------------------------------------------------------------------------
-bool FillPartionedDataSet(vtkPartitionedDataSet* output, const conduit_cpp::Node& node)
+struct FieldMetadata
+{
+  vtkSmartPointer<vtkDataArray> ValuesToReplace = nullptr;
+  vtkSmartPointer<vtkDataArray> ReplacementValues = nullptr;
+  std::string AttributeType;
+
+  static vtkDataSetAttributes::AttributeTypes GetDataSetAttributeType(
+    const std::string& otherAttributeTypeName)
+  {
+    for (int i = 0; i < vtkDataSetAttributes::AttributeTypes::NUM_ATTRIBUTES; ++i)
+    {
+      const std::string attributeTypeName = vtkDataSetAttributes::GetAttributeTypeAsString(i);
+      if (vtksys::SystemTools::UpperCase(otherAttributeTypeName) ==
+        vtksys::SystemTools::UpperCase(attributeTypeName))
+      {
+        return static_cast<vtkDataSetAttributes::AttributeTypes>(i);
+      }
+    }
+    return vtkDataSetAttributes::AttributeTypes::NUM_ATTRIBUTES;
+  }
+
+  static bool IsGhostsAttributeType(const std::string& otherAttributeTypeName)
+  {
+    return vtksys::SystemTools::UpperCase(otherAttributeTypeName) == "GHOSTS";
+  }
+};
+
+//----------------------------------------------------------------------------
+struct ReplaceValuesWorker
+{
+  template <typename Array1T, typename Array2T, typename Array3T>
+  void operator()(Array1T* valuesToReplace, Array2T* replacementValues, Array3T* array) const
+  {
+    const vtkIdType numValuesToReplace = valuesToReplace->GetNumberOfTuples();
+    auto valuesToReplaceRange = vtk::DataArrayValueRange(valuesToReplace);
+    auto replacementValuesRange = vtk::DataArrayValueRange(replacementValues);
+    auto arrayRange = vtk::DataArrayValueRange(array);
+
+    vtkSMPTools::For(0, array->GetNumberOfTuples(),
+      [&](vtkIdType begin, vtkIdType end)
+      {
+        for (vtkIdType inputIdx = begin; inputIdx < end; ++inputIdx)
+        {
+          for (vtkIdType repValueId = 0; repValueId < numValuesToReplace; ++repValueId)
+          {
+            if (valuesToReplaceRange[repValueId] == arrayRange[inputIdx])
+            {
+              arrayRange[inputIdx] = replacementValuesRange[repValueId];
+              break;
+            }
+          }
+        }
+      });
+  }
+};
+
+//----------------------------------------------------------------------------
+bool FillPartitionedDataSet(vtkPartitionedDataSet* output, const conduit_cpp::Node& node)
 {
 #if !VTK_MODULE_ENABLE_VTK_AcceleratorsVTKmDataModel
   // conduit verify_shape_node dereferences the pointer to
@@ -51,8 +115,7 @@ bool FillPartionedDataSet(vtkPartitionedDataSet* output, const conduit_cpp::Node
   // process "topologies".
   auto topologies = node["topologies"];
 
-  conduit_index_t nchildren = topologies.number_of_children();
-  for (conduit_index_t i = 0; i < nchildren; ++i)
+  for (conduit_index_t i = 0, nchildren = topologies.number_of_children(); i < nchildren; ++i)
   {
     auto child = topologies.child(i);
     try
@@ -88,9 +151,73 @@ bool FillPartionedDataSet(vtkPartitionedDataSet* output, const conduit_cpp::Node
     return true;
   }
 
+  // read "state/metadata/vtk_fields"
+  std::map<std::string, FieldMetadata> fieldMetadata;
+  if (node.has_path("state/metadata/vtk_fields"))
+  {
+    auto fieldsMetadata = node["state/metadata/vtk_fields"];
+    for (conduit_index_t i = 0, nchildren = fieldsMetadata.number_of_children(); i < nchildren; ++i)
+    {
+      auto fieldMetadataNode = fieldsMetadata.child(i);
+      const auto& name = fieldMetadataNode.name();
+      try
+      {
+        // read values_to_replace and replacement_values if they exist
+        if (fieldMetadataNode.has_path("values_to_replace") &&
+          fieldMetadataNode.has_path("replacement_values"))
+        {
+          auto valuesToReplace = fieldMetadataNode["values_to_replace"];
+          fieldMetadata[name].ValuesToReplace =
+            vtkConduitArrayUtilities::MCArrayToVTKArray(conduit_cpp::c_node(&valuesToReplace));
+          auto replacementValues = fieldMetadataNode["replacement_values"];
+          fieldMetadata[name].ReplacementValues =
+            vtkConduitArrayUtilities::MCArrayToVTKArray(conduit_cpp::c_node(&replacementValues));
+          if (fieldMetadata[name].ValuesToReplace->GetNumberOfTuples() !=
+            fieldMetadata[name].ReplacementValues->GetNumberOfTuples())
+          {
+            vtkLogF(ERROR,
+              "values_to_replace and replacement_values should have equal size for field '%s'.",
+              name.c_str());
+            return false;
+          }
+          if (fieldMetadata[name].ValuesToReplace->GetNumberOfComponents() != 1 ||
+            fieldMetadata[name].ReplacementValues->GetNumberOfComponents() != 1)
+          {
+            vtkLogF(ERROR,
+              "values_to_replace and replacement_values should have 1 component for field '%s'.",
+              name.c_str());
+            return false;
+          }
+        }
+        // read attribute type if it exists
+        if (fieldMetadataNode.has_path("attribute_type"))
+        {
+          const std::string& attributeType = fieldMetadataNode["attribute_type"].as_string();
+          // check if the attribute type is valid
+          if (FieldMetadata::GetDataSetAttributeType(attributeType) !=
+              vtkDataSetAttributes::AttributeTypes::NUM_ATTRIBUTES ||
+            FieldMetadata::IsGhostsAttributeType(attributeType))
+          {
+            fieldMetadata[name].AttributeType = attributeType;
+          }
+          else
+          {
+            vtkLogF(
+              ERROR, "invalid attribute type '%s' for '%s'.", attributeType.c_str(), name.c_str());
+            return false;
+          }
+        }
+      }
+      catch (std::exception& e)
+      {
+        vtkLogF(ERROR, "failed to process '../state/metadata/vtk_fields/%s'.", name.c_str());
+        vtkLogF(ERROR, "ERROR: \n%s\n", e.what());
+        return false;
+      }
+    }
+  }
   auto fields = node["fields"];
-  nchildren = fields.number_of_children();
-  for (conduit_index_t i = 0; i < nchildren; ++i)
+  for (conduit_index_t i = 0, nchildren = fields.number_of_children(); i < nchildren; ++i)
   {
     auto fieldNode = fields.child(i);
     const auto& fieldname = fieldNode.name();
@@ -111,25 +238,68 @@ bool FillPartionedDataSet(vtkPartitionedDataSet* output, const conduit_cpp::Node
       }
       if (dataset_size > 0)
       {
-        vtkSmartPointer<vtkDataArray> array;
+        // This code path should be removed once MCGhostArrayToVTKGhostArray is removed.
         if (fieldname == "ascent_ghosts")
         {
           // convert ascent ghost information into VTK ghost information
           // the VTK array is named vtkDataSetAttributes::GhostArrayName()
           // and has different values.
-          array = vtkConduitArrayUtilities::MCGhostArrayToVTKGhostArray(
+          auto array = vtkConduitArrayUtilities::MCGhostArrayToVTKGhostArray(
             conduit_cpp::c_node(&values), dsa->IsA("vtkCellData"));
+          dsa->AddArray(array);
+          continue;
         }
-        else
+        vtkSmartPointer<vtkDataArray> array =
+          vtkConduitArrayUtilities::MCArrayToVTKArray(conduit_cpp::c_node(&values), fieldname);
+        if (array->GetNumberOfTuples() != dataset->GetNumberOfElements(vtk_association))
         {
-          array =
-            vtkConduitArrayUtilities::MCArrayToVTKArray(conduit_cpp::c_node(&values), fieldname);
-          if (array->GetNumberOfTuples() != dataset->GetNumberOfElements(vtk_association))
+          throw std::runtime_error("mismatched tuple count!");
+        }
+        if (fieldMetadata.find(fieldname) != fieldMetadata.end())
+        {
+          const auto& metadata = fieldMetadata[fieldname];
+          // replace values if needed
+          if (metadata.ValuesToReplace && metadata.ReplacementValues)
+          {
+            ReplaceValuesWorker replaceValuesWorker;
+            if (!vtkArrayDispatch::Dispatch3SameValueType::Execute(metadata.ValuesToReplace.Get(),
+                  metadata.ReplacementValues.Get(), array.Get(), replaceValuesWorker))
+            {
+              replaceValuesWorker(
+                metadata.ValuesToReplace.Get(), metadata.ReplacementValues.Get(), array.Get());
+            }
+          }
+          // extract the attribute type, and change the array name if needed
+          auto dsaAttributeType = vtkDataSetAttributes::AttributeTypes::NUM_ATTRIBUTES;
+          if (!metadata.AttributeType.empty())
+          {
+            dsaAttributeType = FieldMetadata::GetDataSetAttributeType(metadata.AttributeType);
+            if (FieldMetadata::IsGhostsAttributeType(metadata.AttributeType))
+            {
+              // convert its name to the VTK ghost array name
+              array->SetName(vtkDataSetAttributes::GhostArrayName());
+              // ensure the array is unsigned char
+              if (!array->IsA("vtkUnsignedCharArray"))
+              {
+                auto ghostArray = vtkSmartPointer<vtkUnsignedCharArray>::New();
+                ghostArray->DeepCopy(array);
+                array = ghostArray;
+              }
+            }
+          }
+          if (dsaAttributeType != vtkDataSetAttributes::AttributeTypes::NUM_ATTRIBUTES)
+          {
+            dsa->SetAttribute(array, dsaAttributeType);
+          }
+          else
           {
-            throw std::runtime_error("mismatched tuple count!");
+            dsa->AddArray(array);
           }
         }
-        dsa->AddArray(array);
+        else
+        {
+          dsa->AddArray(array);
+        }
       }
     }
     catch (std::exception& e)
@@ -143,6 +313,12 @@ bool FillPartionedDataSet(vtkPartitionedDataSet* output, const conduit_cpp::Node
   return true;
 }
 
+//----------------------------------------------------------------------------
+bool FillPartionedDataSet(vtkPartitionedDataSet* output, const conduit_cpp::Node& meshNode)
+{
+  return FillPartitionedDataSet(output, meshNode);
+}
+
 //----------------------------------------------------------------------------
 bool FillAMRMesh(vtkOverlappingAMR* amr, const conduit_cpp::Node& node)
 {
diff --git a/IO/CatalystConduit/vtkConduitToDataObject.h b/IO/CatalystConduit/vtkConduitToDataObject.h
index 77e5a3d2dd512a13f2846c0c9859a0ade17daa08..0b4e3cc381cf34760c2c5bf9596579b633510313 100644
--- a/IO/CatalystConduit/vtkConduitToDataObject.h
+++ b/IO/CatalystConduit/vtkConduitToDataObject.h
@@ -10,8 +10,9 @@
 
 #include "vtkIOCatalystConduitModule.h" // For windows import/export of shared libraries
 
-#include "vtkObject.h" // for ABI namespace
-#include "vtkSmartPointer.h"
+#include "vtkDeprecation.h"  // for VTK_DEPRECATED_IN_9_5_0
+#include "vtkObject.h"       // for ABI namespace
+#include "vtkSmartPointer.h" // for vtkSmartPointer
 
 namespace conduit_cpp
 {
@@ -36,6 +37,7 @@ namespace vtkConduitToDataObject
 {
 VTK_ABI_NAMESPACE_BEGIN
 
+///@{
 /**
  * Fill the vtkPartitionedDataSet input.
  * Create concrete vtkDataSet subclass to set it as partition and add arrays in its
@@ -44,8 +46,12 @@ VTK_ABI_NAMESPACE_BEGIN
  * Return true if data was correctly generated, false if an error occurred.
  * Do not throw errors.
  */
+VTKIOCATALYSTCONDUIT_EXPORT bool FillPartitionedDataSet(
+  vtkPartitionedDataSet* output, const conduit_cpp::Node& meshNode);
+VTK_DEPRECATED_IN_9_5_0("Use FillPartitionedDataSet instead.")
 VTKIOCATALYSTCONDUIT_EXPORT bool FillPartionedDataSet(
   vtkPartitionedDataSet* output, const conduit_cpp::Node& meshNode);
+///@}
 
 /**
  * Fill the vtkOverlappingAMR input.
diff --git a/IO/CatalystConduit/vtkDataObjectToConduit.cxx b/IO/CatalystConduit/vtkDataObjectToConduit.cxx
index e188cb5cd4b23fd0daea2bbdd371b0ac499d93d1..80d68bae076b1dcd4093ca020c723bb716795009 100644
--- a/IO/CatalystConduit/vtkDataObjectToConduit.cxx
+++ b/IO/CatalystConduit/vtkDataObjectToConduit.cxx
@@ -529,7 +529,7 @@ bool FillFields(
   vtkFieldData* field_data, const std::string& association, conduit_cpp::Node& conduit_node)
 {
   bool is_success = true;
-
+  auto dataset_attributes = vtkDataSetAttributes::SafeDownCast(field_data);
   int array_count = field_data->GetNumberOfArrays();
   for (int array_index = 0; is_success && array_index < array_count; ++array_index)
   {
@@ -579,6 +579,26 @@ bool FillFields(
 
       auto values_node = field_node["values"];
       is_success = ConvertDataArrayToMCArray(data_array, values_node);
+      if (dataset_attributes)
+      {
+        bool is_dataset_attribute = false;
+        for (int i = 0; i < vtkDataSetAttributes::AttributeTypes::NUM_ATTRIBUTES; ++i)
+        {
+          if (dataset_attributes->GetAttribute(i) == data_array)
+          {
+            auto field_metadata_node = conduit_node["state/metadata/vtk_fields"][name];
+            field_metadata_node["attribute_type"] =
+              vtkDataSetAttributes::GetAttributeTypeAsString(i);
+            is_dataset_attribute = true;
+            break;
+          }
+        }
+        if (!is_dataset_attribute && strcmp(name, vtkDataSetAttributes::GhostArrayName()) == 0)
+        {
+          auto field_metadata_node = conduit_node["state/metadata/vtk_fields"][name];
+          field_metadata_node["attribute_type"] = "Ghosts";
+        }
+      }
     }
     else
     {