diff --git a/src/failure_domain.rs b/src/failure_domain.rs
index e777099bd7864354e0898abd27ac409c795e1cd4..6cc980993577b37fb79f982bc486b1310e963a55 100644
--- a/src/failure_domain.rs
+++ b/src/failure_domain.rs
@@ -34,7 +34,7 @@ use std::collections::{HashMap, HashSet};
 #[derive(Default, PartialEq, Eq, Clone, serde::Deserialize, serde::Serialize)]
 pub struct FailureDomain {
     #[serde(flatten)]
-    data: HashMap<Uppercase, Uppercase>,
+    pub data: HashMap<Uppercase, Uppercase>,
 }
 
 impl FailureDomain {
diff --git a/src/instance.rs b/src/instance.rs
index b81899e1ade64d80c5eede04647543cf7fc8186c..a19d41808530ff9c9018429bac21ebd88a819635 100644
--- a/src/instance.rs
+++ b/src/instance.rs
@@ -54,6 +54,36 @@ pub struct Instance {
 impl Encode for Instance {}
 
 impl Instance {
+    /// Index of field "instance_id" in the space _pico_instance format.
+    ///
+    /// Index of first field is 0.
+    pub const FIELD_INSTANCE_ID: u32 = 0;
+
+    /// Index of field "raft_id" in the space _pico_instance format.
+    ///
+    /// Index of first field is 0.
+    pub const FIELD_RAFT_ID: u32 = 2;
+
+    /// Index of field "failure_domain" in the space _pico_instance format.
+    ///
+    /// Index of first field is 0.
+    pub const FIELD_FAILURE_DOMAIN: u32 = 7;
+
+    pub fn format() -> Vec<tarantool::space::Field> {
+        use tarantool::space::{Field, FieldType};
+        vec![
+            Field::from(("instance_id", FieldType::String)),
+            Field::from(("instance_uuid", FieldType::String)),
+            Field::from(("raft_id", FieldType::Unsigned)),
+            Field::from(("replicaset_id", FieldType::String)),
+            Field::from(("replicaset_uuid", FieldType::String)),
+            Field::from(("current_grade", FieldType::Array)),
+            Field::from(("target_grade", FieldType::Array)),
+            Field::from(("failure_domain", FieldType::Map)),
+            Field::from(("tier", FieldType::String)),
+        ]
+    }
+
     /// Construct an instance.
     pub fn new(
         raft_id: Option<RaftId>,
@@ -611,14 +641,15 @@ mod test {
     use tarantool::tuple::ToTupleBuffer;
 
     #[test]
+    #[rustfmt::skip]
     fn matches_format() {
         let i = Instance::default();
         let tuple_data = i.to_tuple_buffer().unwrap();
-        let format = crate::storage::instance_format();
-        crate::util::check_tuple_matches_format(
-            tuple_data.as_ref(),
-            &format,
-            "define_instance_fields",
-        );
+        let format = Instance::format();
+        crate::util::check_tuple_matches_format(tuple_data.as_ref(), &format, "Instance::format");
+
+        assert_eq!(format[Instance::FIELD_INSTANCE_ID as usize].name, "instance_id");
+        assert_eq!(format[Instance::FIELD_RAFT_ID as usize].name, "raft_id");
+        assert_eq!(format[Instance::FIELD_FAILURE_DOMAIN as usize].name, "failure_domain");
     }
 }
diff --git a/src/storage.rs b/src/storage.rs
index a374682df0b47eeda396551922c481ffe7837178..6025f8db3b0abd5f7156e15882f373b160ce534a 100644
--- a/src/storage.rs
+++ b/src/storage.rs
@@ -14,10 +14,9 @@ use tarantool::tuple::KeyDef;
 use tarantool::tuple::{Decode, DecodeOwned, Encode};
 use tarantool::tuple::{RawBytes, ToTupleBuffer, Tuple, TupleBuffer};
 
-use crate::failure_domain as fd;
-use crate::instance::Grade;
+use crate::failure_domain::FailureDomain;
 use crate::instance::{self, Instance};
-use crate::replicaset::{Replicaset, ReplicasetId};
+use crate::replicaset::Replicaset;
 use crate::schema::Distribution;
 use crate::schema::{IndexDef, SpaceDef};
 use crate::schema::{PrivilegeDef, RoleDef, UserDef};
@@ -1366,28 +1365,28 @@ impl Instances {
         let space_instances = Space::builder(Self::SPACE_NAME)
             .id(Self::SPACE_ID)
             .space_type(SpaceType::DataLocal)
-            .format(instance_format())
+            .format(Instance::format())
             .if_not_exists(true)
             .create()?;
 
         let index_instance_id = space_instances
             .index_builder("instance_id")
             .unique(true)
-            .part(instance_field::InstanceId)
+            .part("instance_id")
             .if_not_exists(true)
             .create()?;
 
         let index_raft_id = space_instances
             .index_builder("raft_id")
             .unique(true)
-            .part(instance_field::RaftId)
+            .part("raft_id")
             .if_not_exists(true)
             .create()?;
 
         let index_replicaset_id = space_instances
             .index_builder("replicaset_id")
             .unique(false)
-            .part(instance_field::ReplicasetId)
+            .part("replicaset_id")
             .if_not_exists(true)
             .create()?;
 
@@ -1422,6 +1421,14 @@ impl Instances {
         Ok(res)
     }
 
+    /// Finds an instance by `id` (see trait [`InstanceId`]).
+    /// Returns the tuple without deserializing.
+    #[inline(always)]
+    pub fn get_raw(&self, id: &impl InstanceId) -> Result<Tuple> {
+        let res = id.find_in(self)?;
+        Ok(res)
+    }
+
     /// Checks if an instance with `id` (see trait [`InstanceId`]) is present.
     #[inline]
     pub fn contains(&self, id: &impl InstanceId) -> Result<bool> {
@@ -1432,29 +1439,6 @@ impl Instances {
         }
     }
 
-    /// Finds an instance by `id` (see `InstanceId`) and return a single field
-    /// specified by `F` (see `InstanceFieldDef` & `instance_field` module).
-    #[inline(always)]
-    pub fn field<F>(&self, id: &impl InstanceId) -> Result<F::Type>
-    where
-        F: InstanceFieldDef,
-    {
-        let tuple = id.find_in(self)?;
-        let res = F::get_in(&tuple)?;
-        Ok(res)
-    }
-
-    /// Returns an iterator over all instances. Items of the iterator are
-    /// specified by `F` (see `InstanceFieldDef` & `instance_field` module).
-    #[inline(always)]
-    pub fn instances_fields<F>(&self) -> Result<InstancesFields<F>>
-    where
-        F: InstanceFieldDef,
-    {
-        let iter = self.space.select(IteratorType::All, &())?;
-        Ok(InstancesFields::new(iter))
-    }
-
     #[inline]
     pub fn all_instances(&self) -> tarantool::Result<Vec<Instance>> {
         self.space
@@ -1473,31 +1457,34 @@ impl Instances {
         Ok(EntryIter::new(iter))
     }
 
-    pub fn replicaset_fields<T>(
-        &self,
-        replicaset_id: &ReplicasetId,
-    ) -> tarantool::Result<Vec<T::Type>>
-    where
-        T: InstanceFieldDef,
-    {
-        self.index_replicaset_id
-            .select(IteratorType::Eq, &[replicaset_id])?
-            .map(|tuple| T::get_in(&tuple))
-            .collect()
-    }
-
-    pub fn max_raft_id(&self) -> tarantool::Result<RaftId> {
-        match self.index_raft_id.max(&())? {
-            None => Ok(0),
-            Some(tuple) => instance_field::RaftId::get_in(&tuple),
-        }
+    pub fn max_raft_id(&self) -> Result<RaftId> {
+        let Some(tuple) = self.index_raft_id.max(&())? else {
+            return Ok(0);
+        };
+        let Some(raft_id) = tuple.field(Instance::FIELD_RAFT_ID)? else {
+            return Err(Error::StorageCorrupted {
+                field: "raft_id".into(),
+                table: "_pico_instance".into(),
+            });
+        };
+        Ok(raft_id)
     }
 
     pub fn failure_domain_names(&self) -> Result<HashSet<Uppercase>> {
-        Ok(self
-            .instances_fields::<instance_field::FailureDomain>()?
-            .flat_map(|fd| fd.names().cloned().collect::<Vec<_>>())
-            .collect())
+        let mut res = HashSet::with_capacity(16);
+        for tuple in self.space.select(IteratorType::All, &())? {
+            let Some(failure_domain) = tuple.field(Instance::FIELD_FAILURE_DOMAIN)? else {
+                return Err(Error::StorageCorrupted {
+                    field: "failure_domain".into(),
+                    table: "_pico_instance".into(),
+                });
+            };
+            let failure_domain: FailureDomain = failure_domain;
+            for name in failure_domain.data.into_keys() {
+                res.insert(name);
+            }
+        }
+        Ok(res)
     }
 }
 
@@ -1510,138 +1497,6 @@ impl ToEntryIter for Instances {
     }
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// InstanceField
-////////////////////////////////////////////////////////////////////////////////
-
-macro_rules! define_instance_fields {
-    ($($field:ident: $ty:ty = ($name:literal, $tt_ty:path))+) => {
-        ::tarantool::define_str_enum! {
-            /// An enumeration of raft_space field names
-            pub enum InstanceField {
-                $($field = $name,)+
-            }
-        }
-
-        pub mod instance_field {
-            use super::*;
-            $(
-                /// Helper struct that represents
-                #[doc = stringify!($name)]
-                /// field of [`Instance`].
-                ///
-                /// It's rust type is
-                #[doc = concat!("`", stringify!($ty), "`")]
-                /// and it's tarantool type is
-                #[doc = concat!("`", stringify!($tt_ty), "`")]
-                ///
-                /// [`Instance`]: crate::instance::Instance
-                pub struct $field;
-
-                impl InstanceFieldDef for $field {
-                    type Type = $ty;
-
-                    fn get_in(tuple: &Tuple) -> tarantool::Result<Self::Type> {
-                        Ok(tuple.try_get($name)?.expect("instance fields aren't nullable"))
-                    }
-                }
-
-                impl From<$field> for ::tarantool::index::Part {
-                    #[inline(always)]
-                    fn from(_: $field) -> ::tarantool::index::Part {
-                        $name.into()
-                    }
-                }
-
-                impl From<$field> for ::tarantool::space::Field {
-                    #[inline(always)]
-                    fn from(_: $field) -> ::tarantool::space::Field {
-                        ($name, $tt_ty).into()
-                    }
-                }
-
-                impl ::tarantool::tuple::TupleIndex for $field {
-                    #[inline(always)]
-                    fn get_field<'a, T>(self, tuple: &'a Tuple) -> ::tarantool::Result<Option<T>>
-                    where
-                        T: ::tarantool::tuple::Decode<'a>,
-                    {
-                        $name.get_field(tuple)
-                    }
-                }
-            )+
-        }
-
-        pub fn instance_format() -> Vec<::tarantool::space::Field> {
-            vec![
-                $( ::tarantool::space::Field::from(($name, $tt_ty)), )+
-            ]
-        }
-    };
-}
-
-define_instance_fields! {
-    InstanceId     : instance::InstanceId = ("instance_id",     FieldType::String)
-    InstanceUuid   : String               = ("instance_uuid",   FieldType::String)
-    RaftId         : traft::RaftId        = ("raft_id",         FieldType::Unsigned)
-    ReplicasetId   : String               = ("replicaset_id",   FieldType::String)
-    ReplicasetUuid : String               = ("replicaset_uuid", FieldType::String)
-    CurrentGrade   : Grade                = ("current_grade",   FieldType::Array)
-    TargetGrade    : Grade                = ("target_grade",    FieldType::Array)
-    FailureDomain  : fd::FailureDomain    = ("failure_domain",  FieldType::Map)
-    Tier           : String               = ("tier",            FieldType::String)
-}
-
-impl tarantool::tuple::TupleIndex for InstanceField {
-    fn get_field<'a, T>(self, tuple: &'a Tuple) -> tarantool::Result<Option<T>>
-    where
-        T: tarantool::tuple::Decode<'a>,
-    {
-        self.as_str().get_field(tuple)
-    }
-}
-
-/// A helper trait for type-safe and efficient access to a Instance's fields
-/// without deserializing the whole tuple.
-///
-/// This trait contains information needed to define and use a given tuple field.
-pub trait InstanceFieldDef {
-    /// Rust type of the field.
-    ///
-    /// Used when decoding the field.
-    type Type: tarantool::tuple::DecodeOwned;
-
-    /// Get the field in `tuple`.
-    fn get_in(tuple: &Tuple) -> tarantool::Result<Self::Type>;
-}
-
-macro_rules! define_instance_field_def_for_tuples {
-    () => {};
-    ($h:ident $($t:ident)*) => {
-        impl<$h, $($t),*> InstanceFieldDef for ($h, $($t),*)
-        where
-            $h: InstanceFieldDef,
-            $h::Type: serde::de::DeserializeOwned,
-            $(
-                $t: InstanceFieldDef,
-                $t::Type: serde::de::DeserializeOwned,
-            )*
-        {
-            type Type = ($h::Type, $($t::Type),*);
-
-            fn get_in(tuple: &Tuple) -> tarantool::Result<Self::Type> {
-                Ok(($h::get_in(&tuple)?, $($t::get_in(&tuple)?,)*))
-            }
-        }
-
-        define_instance_field_def_for_tuples!{ $($t)* }
-    };
-}
-
-define_instance_field_def_for_tuples! {
-    T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // InstanceId
 ////////////////////////////////////////////////////////////////////////////////
@@ -1672,36 +1527,6 @@ impl InstanceId for instance::InstanceId {
     }
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// InstancesFields
-////////////////////////////////////////////////////////////////////////////////
-
-pub struct InstancesFields<F> {
-    iter: IndexIterator,
-    marker: PhantomData<F>,
-}
-
-impl<F> InstancesFields<F> {
-    fn new(iter: IndexIterator) -> Self {
-        Self {
-            iter,
-            marker: PhantomData,
-        }
-    }
-}
-
-impl<F> Iterator for InstancesFields<F>
-where
-    F: InstanceFieldDef,
-{
-    type Item = F::Type;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        let res = self.iter.next().as_ref().map(F::get_in);
-        res.map(|res| res.expect("instance should decode correctly"))
-    }
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // EntryIter
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/traft/error.rs b/src/traft/error.rs
index 810d0bfb64b7ec1c4b70912726da0b9bf14168e6..d212bbbdfee375063b29eb72998a3b9de511a12e 100644
--- a/src/traft/error.rs
+++ b/src/traft/error.rs
@@ -76,6 +76,9 @@ pub enum Error {
     #[error("transaction: {0}")]
     Transaction(String),
 
+    #[error("storage corrupted: failed to decode field '{field}' from table '{table}'")]
+    StorageCorrupted { table: String, field: String },
+
     #[error("{0}")]
     Other(Box<dyn std::error::Error>),
 }
diff --git a/src/traft/network.rs b/src/traft/network.rs
index cadc9908ddf71f6f81206a0a9eb5cd1d1f4d858c..2595bf8f238fb35dec96e99996de819dc11137ac 100644
--- a/src/traft/network.rs
+++ b/src/traft/network.rs
@@ -1,8 +1,9 @@
+use crate::instance::Instance;
 use crate::instance::InstanceId;
 use crate::mailbox::Mailbox;
 use crate::reachability::InstanceReachabilityManagerRef;
 use crate::rpc;
-use crate::storage::{instance_field, Clusterwide, Instances, PeerAddresses};
+use crate::storage::{Clusterwide, Instances, PeerAddresses};
 use crate::tlog;
 use crate::traft;
 use crate::traft::error::Error;
@@ -430,11 +431,10 @@ impl ConnectionPool {
         if let Some(worker) = workers.get(&raft_id) {
             Ok(worker)
         } else {
-            let instance_id = self
-                .instances
-                .field::<instance_field::InstanceId>(&raft_id)
-                .map_err(|_| Error::NoInstanceWithRaftId(raft_id))
-                .ok();
+            let mut instance_id: Option<InstanceId> = None;
+            if let Ok(tuple) = self.instances.get_raw(&raft_id) {
+                instance_id = tuple.field(Instance::FIELD_INSTANCE_ID)?;
+            }
             // Check if address of this peer is known.
             // No need to store the result,
             // because it will be updated in the loop
@@ -468,10 +468,10 @@ impl ConnectionPool {
             Ok(worker)
         } else {
             let instance_id = InstanceId::from(instance_id);
-            let raft_id = self
-                .instances
-                .field::<instance_field::RaftId>(&instance_id)
-                .map_err(|_| Error::NoInstanceWithInstanceId(instance_id.clone()))?;
+            let tuple = self.instances.get_raw(&instance_id)?;
+            let Some(raft_id) = tuple.field(Instance::FIELD_RAFT_ID)? else {
+                return Err(Error::other("storage corrupted: couldn't decode instance's raft id"));
+            };
             self.get_or_create_by_raft_id(raft_id)
         }
     }