Repository: tafia/quick-xml
Pull request #675 (2023-10-28 22:05:20)

Rework errors
This PR does cleanup of our errors, making them more consistent. In particular, now syntax errors decoupled from other errors and this will allow us to have `no_std` XML parser in the future.

In addition, I also review the way how errors is reported by the serde deserializer. I already wrote my points about correct deserializer behavior [here](https://github.com/serde-rs/serde/pull/2639#issuecomment-1783793554) and in this PR I implement them -- I avoid to return errors if requested data does not match existing data. Instead deserializer will provide the data and the `Visitor` will return an error if it wish.


Patch:
diff --git a/Cargo.toml b/Cargo.toml
index b8299b9..4118980 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,7 +16,7 @@ include = ["src/*", "LICENSE-MIT.md", "README.md"]
 [dependencies]
 document-features = { version = "0.2", optional = true }
 encoding_rs = { version = "0.8", optional = true }
-serde = { version = ">=1.0.100", optional = true }
+serde = { version = ">=1.0.139", optional = true }
 tokio = { version = "1.10", optional = true, default-features = false, features = ["io-util"] }
 memchr = "2.1"
 arbitrary = { version = "1", features = ["derive"], optional = true }
diff --git a/Changelog.md b/Changelog.md
index f416a71..40cce46 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -16,6 +16,18 @@
 
 ### Misc Changes
 
+- [#675]: Minimum supported version of serde raised to 1.0.139
+- [#675]: Rework the `quick_xml::Error` type to provide more accurate information:
+  - `Error::EndEventMismatch` replaced by `IllFormedError::MismatchedEnd` in some cases
+  - `Error::EndEventMismatch` replaced by `IllFormedError::UnmatchedEnd` in some cases
+  - `Error::TextNotFound` was removed because not used
+  - `Error::UnexpectedBang` replaced by `SyntaxError`
+  - `Error::UnexpectedEof` replaced by `SyntaxError` in some cases
+  - `Error::UnexpectedEof` replaced by `IllFormedError` in some cases
+  - `Error::UnexpectedToken` replaced by `IllFormedError::DoubleHyphenInComment`
+
+[#675]: https://github.com/tafia/quick-xml/pull/675
+
 
 ## 0.31.0 -- 2023-10-22
 
diff --git a/examples/read_nodes.rs b/examples/read_nodes.rs
index e7ea77e..07a7ad6 100644
--- a/examples/read_nodes.rs
+++ b/examples/read_nodes.rs
@@ -2,6 +2,7 @@
 // Note: for this specific data set using serde feature would simplify
 //       this simple data is purely to make it easier to understand the code
 
+use quick_xml::events::attributes::AttrError;
 use quick_xml::events::{BytesStart, Event};
 use quick_xml::name::QName;
 use quick_xml::reader::Reader;
@@ -29,6 +30,26 @@ const XML: &str = r#"
   </Localization>
 "#;
 
+#[derive(Debug)]
+enum AppError {
+    /// XML parsing error
+    Xml(quick_xml::Error),
+    /// The `Translation/Text` node is missed
+    NoText(String),
+}
+
+impl From<quick_xml::Error> for AppError {
+    fn from(error: quick_xml::Error) -> Self {
+        Self::Xml(error)
+    }
+}
+
+impl From<AttrError> for AppError {
+    fn from(error: AttrError) -> Self {
+        Self::Xml(quick_xml::Error::InvalidAttr(error))
+    }
+}
+
 #[derive(Debug)]
 struct Translation {
     tag: String,
@@ -40,7 +61,7 @@ impl Translation {
     fn new_from_element(
         reader: &mut Reader<&[u8]>,
         element: BytesStart,
-    ) -> Result<Translation, quick_xml::Error> {
+    ) -> Result<Translation, AppError> {
         let mut tag = Cow::Borrowed("");
         let mut lang = Cow::Borrowed("");
 
@@ -68,16 +89,16 @@ impl Translation {
             } else {
                 dbg!("Expected Event::Start for Text, got: {:?}", &event);
                 let name_string = reader.decoder().decode(name.as_ref())?;
-                Err(quick_xml::Error::UnexpectedToken(name_string.into()))
+                Err(AppError::NoText(name_string.into()))
             }
         } else {
             let event_string = format!("{:?}", event);
-            Err(quick_xml::Error::UnexpectedToken(event_string))
+            Err(AppError::NoText(event_string))
         }
     }
 }
 
-fn main() -> Result<(), quick_xml::Error> {
+fn main() -> Result<(), AppError> {
     // In a real-world use case, Settings would likely be a struct
     // HashMap here is just to make the sample code short
     let mut settings: HashMap<String, String>;
diff --git a/src/de/key.rs b/src/de/key.rs
index 2645d90..3219ef6 100644
--- a/src/de/key.rs
+++ b/src/de/key.rs
@@ -1,9 +1,10 @@
+use crate::de::simple_type::UnitOnly;
 use crate::de::str2bool;
 use crate::encoding::Decoder;
 use crate::errors::serialize::DeError;
 use crate::name::QName;
 use crate::utils::CowRef;
-use serde::de::{DeserializeSeed, Deserializer, EnumAccess, VariantAccess, Visitor};
+use serde::de::{DeserializeSeed, Deserializer, EnumAccess, Visitor};
 use serde::{forward_to_deserialize_any, serde_if_integer128};
 use std::borrow::Cow;
 
@@ -240,60 +241,14 @@ impl<'de, 'd> Deserializer<'de> for QNameDeserializer<'de, 'd> {
 
 impl<'de, 'd> EnumAccess<'de> for QNameDeserializer<'de, 'd> {
     type Error = DeError;
-    type Variant = QNameUnitOnly;
+    type Variant = UnitOnly;
 
     fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
     where
         V: DeserializeSeed<'de>,
     {
         let name = seed.deserialize(self)?;
-        Ok((name, QNameUnitOnly))
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/// Deserializer of variant data, that supports only unit variants.
-/// Attempt to deserialize newtype, tuple or struct variant will return a
-/// [`DeError::Unsupported`] error.
-pub struct QNameUnitOnly;
-impl<'de> VariantAccess<'de> for QNameUnitOnly {
-    type Error = DeError;
-
-    #[inline]
-    fn unit_variant(self) -> Result<(), DeError> {
-        Ok(())
-    }
-
-    fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, DeError>
-    where
-        T: DeserializeSeed<'de>,
-    {
-        Err(DeError::Unsupported(
-            "enum newtype variants are not supported as an XML names".into(),
-        ))
-    }
-
-    fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, DeError>
-    where
-        V: Visitor<'de>,
-    {
-        Err(DeError::Unsupported(
-            "enum tuple variants are not supported as an XML names".into(),
-        ))
-    }
-
-    fn struct_variant<V>(
-        self,
-        _fields: &'static [&'static str],
-        _visitor: V,
-    ) -> Result<V::Value, DeError>
-    where
-        V: Visitor<'de>,
-    {
-        Err(DeError::Unsupported(
-            "enum struct variants are not supported as an XML names".into(),
-        ))
+        Ok((name, UnitOnly))
     }
 }
 
@@ -405,7 +360,7 @@ mod tests {
                 match err {
                     DeError::$kind(e) => assert_eq!(e, $reason),
                     _ => panic!(
-                        "Expected `{}({})`, found `{:?}`",
+                        "Expected `Err({}({}))`, but got `{:?}`",
                         stringify!($kind),
                         $reason,
                         err
@@ -473,11 +428,11 @@ mod tests {
     deserialized_to!(enum_unit: Enum = "Unit" => Enum::Unit);
     deserialized_to!(enum_unit_for_attr: Enum = "@Attr" => Enum::Attr);
     err!(enum_newtype: Enum = "Newtype"
-        => Unsupported("enum newtype variants are not supported as an XML names"));
+        => Custom("invalid type: unit value, expected a string"));
     err!(enum_tuple: Enum = "Tuple"
-        => Unsupported("enum tuple variants are not supported as an XML names"));
+        => Custom("invalid type: unit value, expected tuple variant Enum::Tuple"));
     err!(enum_struct: Enum = "Struct"
-        => Unsupported("enum struct variants are not supported as an XML names"));
+        => Custom("invalid type: unit value, expected struct variant Enum::Struct"));
 
     // Field identifiers cannot be serialized, and IgnoredAny represented _something_
     // which is not concrete
diff --git a/src/de/map.rs b/src/de/map.rs
index 97e632d..e229c60 100644
--- a/src/de/map.rs
+++ b/src/de/map.rs
@@ -8,6 +8,7 @@ use crate::{
     de::{str2bool, DeEvent, Deserializer, XmlRead, TEXT_KEY, VALUE_KEY},
     encoding::Decoder,
     errors::serialize::DeError,
+    errors::Error,
     events::attributes::IterState,
     events::BytesStart,
     name::QName,
@@ -300,7 +301,7 @@ where
                 }
                 // We cannot get `Eof` legally, because we always inside of the
                 // opened tag `self.start`
-                DeEvent::Eof => Err(DeError::UnexpectedEof),
+                DeEvent::Eof => Err(Error::missed_end(self.start.name(), decoder).into()),
             }
         }
     }
@@ -616,9 +617,9 @@ where
         if self.fixed_name {
             match self.map.de.next()? {
                 // Handles <field>UnitEnumVariant</field>
-                DeEvent::Start(_) => {
+                DeEvent::Start(e) => {
                     // skip <field>, read text after it and ensure that it is ended by </field>
-                    let text = self.map.de.read_text()?;
+                    let text = self.map.de.read_text(e.name())?;
                     if text.is_empty() {
                         // Map empty text (<field/>) to a special `$text` variant
                         visitor.visit_enum(SimpleTypeDeserializer::from_text(TEXT_KEY.into()))
@@ -669,8 +670,8 @@ where
                 seed.deserialize(BorrowedStrDeserializer::<DeError>::new(TEXT_KEY))?,
                 true,
             ),
-            DeEvent::End(e) => return Err(DeError::UnexpectedEnd(e.name().into_inner().to_vec())),
-            DeEvent::Eof => return Err(DeError::UnexpectedEof),
+            // SAFETY: we use that deserializer only when we peeked `Start` or `Text` event
+            _ => unreachable!(),
         };
         Ok((
             name,
@@ -927,12 +928,14 @@ where
                 DeEvent::Start(e) if !self.filter.is_suitable(e, decoder)? => Ok(None),
 
                 // Stop iteration after reaching a closing tag
-                DeEvent::End(e) if e.name() == self.map.start.name() => Ok(None),
-                // This is a unmatched closing tag, so the XML is invalid
-                DeEvent::End(e) => Err(DeError::UnexpectedEnd(e.name().as_ref().to_owned())),
+                // The matching tag name is guaranteed by the reader
+                DeEvent::End(e) => {
+                    debug_assert_eq!(self.map.start.name(), e.name());
+                    Ok(None)
+                }
                 // We cannot get `Eof` legally, because we always inside of the
                 // opened tag `self.map.start`
-                DeEvent::Eof => Err(DeError::UnexpectedEof),
+                DeEvent::Eof => Err(Error::missed_end(self.map.start.name(), decoder).into()),
 
                 DeEvent::Text(_) => match self.map.de.next()? {
                     DeEvent::Text(e) => seed.deserialize(TextDeserializer(e)).map(Some),
@@ -1018,7 +1021,7 @@ where
     /// [`CData`]: crate::events::Event::CData
     #[inline]
     fn read_string(&mut self) -> Result<Cow<'de, str>, DeError> {
-        self.de.read_text()
+        self.de.read_text(self.start.name())
     }
 }
 
diff --git a/src/de/mod.rs b/src/de/mod.rs
index a7190f6..d721010 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -509,8 +509,9 @@
 //!   /// Use unit variant, if you do not care of a content.
 //!   /// You can use tuple variant if you want to parse
 //!   /// textual content as an xs:list.
-//!   /// Struct variants are not supported and will return
-//!   /// Err(Unsupported)
+//!   /// Struct variants are will pass a string to the
+//!   /// struct enum variant visitor, which typically
+//!   /// returns Err(Custom)
 //!   #[serde(rename = "$text")]
 //!   Text(String),
 //! }
@@ -613,8 +614,9 @@
 //!   /// Use unit variant, if you do not care of a content.
 //!   /// You can use tuple variant if you want to parse
 //!   /// textual content as an xs:list.
-//!   /// Struct variants are not supported and will return
-//!   /// Err(Unsupported)
+//!   /// Struct variants are will pass a string to the
+//!   /// struct enum variant visitor, which typically
+//!   /// returns Err(Custom)
 //!   #[serde(rename = "$text")]
 //!   Text(String),
 //! }
@@ -1377,9 +1379,9 @@
 //! |Kind   |Top-level and in `$value` field          |In normal field      |In `$text` field     |
 //! |-------|-----------------------------------------|---------------------|---------------------|
 //! |Unit   |`<Unit/>`                                |`<field>Unit</field>`|`Unit`               |
-//! |Newtype|`<Newtype>42</Newtype>`                  |Err(Unsupported)     |Err(Unsupported)     |
-//! |Tuple  |`<Tuple>42</Tuple><Tuple>answer</Tuple>` |Err(Unsupported)     |Err(Unsupported)     |
-//! |Struct |`<Struct><q>42</q><a>answer</a></Struct>`|Err(Unsupported)     |Err(Unsupported)     |
+//! |Newtype|`<Newtype>42</Newtype>`                  |Err(Custom) [^0]     |Err(Custom) [^0]     |
+//! |Tuple  |`<Tuple>42</Tuple><Tuple>answer</Tuple>` |Err(Custom) [^0]     |Err(Custom) [^0]     |
+//! |Struct |`<Struct><q>42</q><a>answer</a></Struct>`|Err(Custom) [^0]     |Err(Custom) [^0]     |
 //!
 //! `$text` enum variant
 //! --------------------
@@ -1387,9 +1389,13 @@
 //! |Kind   |Top-level and in `$value` field          |In normal field      |In `$text` field     |
 //! |-------|-----------------------------------------|---------------------|---------------------|
 //! |Unit   |_(empty)_                                |`<field/>`           |_(empty)_            |
-//! |Newtype|`42`                                     |Err(Unsupported) [^1]|Err(Unsupported) [^2]|
-//! |Tuple  |`42 answer`                              |Err(Unsupported) [^3]|Err(Unsupported) [^4]|
-//! |Struct |Err(Unsupported)                         |Err(Unsupported)     |Err(Unsupported)     |
+//! |Newtype|`42`                                     |Err(Custom) [^0] [^1]|Err(Custom) [^0] [^2]|
+//! |Tuple  |`42 answer`                              |Err(Custom) [^0] [^3]|Err(Custom) [^0] [^4]|
+//! |Struct |Err(Custom) [^0]                         |Err(Custom) [^0]     |Err(Custom) [^0]     |
+//!
+//! [^0]: Error is returned by the deserialized type. In case of derived implementation a `Custom`
+//!       error will be returned, but custom deserialize implementation can successfully deserialize
+//!       value from a string which will be passed to it.
 //!
 //! [^1]: If this serialize as `<field>42</field>` then it will be ambiguity during deserialization,
 //!       because it clash with `Unit` representation in normal field.
@@ -1861,6 +1867,7 @@ macro_rules! deserialize_primitives {
         }
 
         /// Character represented as [strings](#method.deserialize_str).
+        #[inline]
         fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, DeError>
         where
             V: Visitor<'de>,
@@ -1880,6 +1887,7 @@ macro_rules! deserialize_primitives {
         }
 
         /// Representation of owned strings the same as [non-owned](#method.deserialize_str).
+        #[inline]
         fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, DeError>
         where
             V: Visitor<'de>,
@@ -1887,15 +1895,17 @@ macro_rules! deserialize_primitives {
             self.deserialize_str(visitor)
         }
 
-        /// Returns [`DeError::Unsupported`]
-        fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value, DeError>
+        /// Forwards deserialization to the [`deserialize_any`](#method.deserialize_any).
+        #[inline]
+        fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, DeError>
         where
             V: Visitor<'de>,
         {
-            Err(DeError::Unsupported("binary data content is not supported by XML format".into()))
+            self.deserialize_any(visitor)
         }
 
         /// Forwards deserialization to the [`deserialize_bytes`](#method.deserialize_bytes).
+        #[inline]
         fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, DeError>
         where
             V: Visitor<'de>,
@@ -1904,6 +1914,7 @@ macro_rules! deserialize_primitives {
         }
 
         /// Representation of the named units the same as [unnamed units](#method.deserialize_unit).
+        #[inline]
         fn deserialize_unit_struct<V>(
             self,
             _name: &'static str,
@@ -1916,6 +1927,7 @@ macro_rules! deserialize_primitives {
         }
 
         /// Representation of tuples the same as [sequences](#method.deserialize_seq).
+        #[inline]
         fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, DeError>
         where
             V: Visitor<'de>,
@@ -1924,6 +1936,7 @@ macro_rules! deserialize_primitives {
         }
 
         /// Representation of named tuples the same as [unnamed tuples](#method.deserialize_tuple).
+        #[inline]
         fn deserialize_tuple_struct<V>(
             self,
             _name: &'static str,
@@ -1947,6 +1960,7 @@ macro_rules! deserialize_primitives {
         }
 
         /// Identifiers represented as [strings](#method.deserialize_str).
+        #[inline]
         fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, DeError>
         where
             V: Visitor<'de>,
@@ -2619,7 +2633,7 @@ where
     /// |Event             |XML                        |Handling
     /// |------------------|---------------------------|----------------------------------------
     /// |[`DeEvent::Start`]|`<tag>...</tag>`           |if `allow_start == true`, result determined by the second table, otherwise emits [`UnexpectedStart("tag")`](DeError::UnexpectedStart)
-    /// |[`DeEvent::End`]  |`</any-tag>`               |Emits [`UnexpectedEnd("any-tag")`](DeError::UnexpectedEnd)
+    /// |[`DeEvent::End`]  |`</any-tag>`               |This is impossible situation, the method will panic if it happens
     /// |[`DeEvent::Text`] |`text content` or `<![CDATA[cdata content]]>` (probably mixed)|Returns event content unchanged
     /// |[`DeEvent::Eof`]  |                           |Emits [`UnexpectedEof`](DeError::UnexpectedEof)
     ///
@@ -2630,7 +2644,7 @@ where
     /// |[`DeEvent::Start`]|`<any-tag>...</any-tag>`   |Emits [`UnexpectedStart("any-tag")`](DeError::UnexpectedStart)
     /// |[`DeEvent::End`]  |`</tag>`                   |Returns an empty slice. The reader guarantee that tag will match the open one
     /// |[`DeEvent::Text`] |`text content` or `<![CDATA[cdata content]]>` (probably mixed)|Returns event content unchanged, expects the `</tag>` after that
-    /// |[`DeEvent::Eof`]  |                           |Emits [`UnexpectedEof`](DeError::UnexpectedEof)
+    /// |[`DeEvent::Eof`]  |                           |Emits [`InvalidXml(IllFormed(MissedEnd))`](DeError::InvalidXml)
     ///
     /// [`Text`]: Event::Text
     /// [`CData`]: Event::CData
@@ -2638,15 +2652,21 @@ where
         match self.next()? {
             DeEvent::Text(e) => Ok(e.text),
             // allow one nested level
-            DeEvent::Start(_) if allow_start => self.read_text(),
+            DeEvent::Start(e) if allow_start => self.read_text(e.name()),
             DeEvent::Start(e) => Err(DeError::UnexpectedStart(e.name().as_ref().to_owned())),
-            DeEvent::End(e) => Err(DeError::UnexpectedEnd(e.name().as_ref().to_owned())),
+            // SAFETY: The reader is guaranteed that we don't have unmatched tags
+            // If we here, then out deserializer has a bug
+            DeEvent::End(e) => unreachable!("{:?}", e),
             DeEvent::Eof => Err(DeError::UnexpectedEof),
         }
     }
     /// Consumes one [`DeEvent::Text`] event and ensures that it is followed by the
     /// [`DeEvent::End`] event.
-    fn read_text(&mut self) -> Result<Cow<'de, str>, DeError> {
+    ///
+    /// # Parameters
+    /// - `name`: name of a tag opened before reading text. The corresponding end tag
+    ///   should present in input just after the text
+    fn read_text(&mut self, name: QName) -> Result<Cow<'de, str>, DeError> {
         match self.next()? {
             DeEvent::Text(e) => match self.next()? {
                 // The matching tag name is guaranteed by the reader
@@ -2654,14 +2674,14 @@ where
                 // SAFETY: Cannot be two consequent Text events, they would be merged into one
                 DeEvent::Text(_) => unreachable!(),
                 DeEvent::Start(e) => Err(DeError::UnexpectedStart(e.name().as_ref().to_owned())),
-                DeEvent::Eof => Err(DeError::UnexpectedEof),
+                DeEvent::Eof => Err(Error::missed_end(name, self.reader.decoder()).into()),
             },
             // We can get End event in case of `<tag></tag>` or `<tag/>` input
             // Return empty text in that case
             // The matching tag name is guaranteed by the reader
             DeEvent::End(_) => Ok("".into()),
             DeEvent::Start(s) => Err(DeError::UnexpectedStart(s.name().as_ref().to_owned())),
-            DeEvent::Eof => Err(DeError::UnexpectedEof),
+            DeEvent::Eof => Err(Error::missed_end(name, self.reader.decoder()).into()),
         }
     }
 
@@ -2816,8 +2836,16 @@ where
     {
         match self.next()? {
             DeEvent::Start(e) => visitor.visit_map(ElementMapAccess::new(self, e, fields)?),
-            DeEvent::End(e) => Err(DeError::UnexpectedEnd(e.name().as_ref().to_owned())),
-            DeEvent::Text(_) => Err(DeError::ExpectedStart),
+            // SAFETY: The reader is guaranteed that we don't have unmatched tags
+            // If we here, then out deserializer has a bug
+            DeEvent::End(e) => unreachable!("{:?}", e),
+            // Deserializer methods are only hints, if deserializer could not satisfy
+            // request, it should return the data that it has. It is responsibility
+            // of a Visitor to return an error if it does not understand the data
+            DeEvent::Text(e) => match e.text {
+                Cow::Borrowed(s) => visitor.visit_borrowed_str(s),
+                Cow::Owned(s) => visitor.visit_string(s),
+            },
             DeEvent::Eof => Err(DeError::UnexpectedEof),
         }
     }
@@ -2836,7 +2864,7 @@ where
     /// |Event             |XML                        |Handling
     /// |------------------|---------------------------|-------------------------------------------
     /// |[`DeEvent::Start`]|`<tag>...</tag>`           |Calls `visitor.visit_unit()`, consumes all events up to and including corresponding `End` event
-    /// |[`DeEvent::End`]  |`</tag>`                   |Emits [`UnexpectedEnd("tag")`](DeError::UnexpectedEnd)
+    /// |[`DeEvent::End`]  |`</tag>`                   |This is impossible situation, the method will panic if it happens
     /// |[`DeEvent::Text`] |`text content` or `<![CDATA[cdata content]]>` (probably mixed)|Calls `visitor.visit_unit()`. The content is ignored
     /// |[`DeEvent::Eof`]  |                           |Emits [`UnexpectedEof`](DeError::UnexpectedEof)
     fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, DeError>
@@ -2849,7 +2877,9 @@ where
                 visitor.visit_unit()
             }
             DeEvent::Text(_) => visitor.visit_unit(),
-            DeEvent::End(e) => Err(DeError::UnexpectedEnd(e.name().as_ref().to_owned())),
+            // SAFETY: The reader is guaranteed that we don't have unmatched tags
+            // If we here, then out deserializer has a bug
+            DeEvent::End(e) => unreachable!("{:?}", e),
             DeEvent::Eof => Err(DeError::UnexpectedEof),
         }
     }
@@ -3029,7 +3059,6 @@ impl<'i, R: BufRead> XmlRead<'i> for IoReader<R> {
 
     fn read_to_end(&mut self, name: QName) -> Result<(), DeError> {
         match self.reader.read_to_end_into(name, &mut self.buf) {
-            Err(Error::UnexpectedEof(_)) => Err(DeError::UnexpectedEof),
             Err(e) => Err(e.into()),
             Ok(_) => Ok(()),
         }
@@ -3061,7 +3090,6 @@ impl<'de> XmlRead<'de> for SliceReader<'de> {
 
     fn read_to_end(&mut self, name: QName) -> Result<(), DeError> {
         match self.reader.read_to_end(name) {
-            Err(Error::UnexpectedEof(_)) => Err(DeError::UnexpectedEof),
             Err(e) => Err(e.into()),
             Ok(_) => Ok(()),
         }
@@ -3075,6 +3103,7 @@ impl<'de> XmlRead<'de> for SliceReader<'de> {
 #[cfg(test)]
 mod tests {
     use super::*;
+    use crate::errors::IllFormedError;
     use pretty_assertions::assert_eq;
 
     fn make_de<'de>(source: &'de str) -> Deserializer<'de, SliceReader<'de>> {
@@ -3539,7 +3568,7 @@ mod tests {
 
             match List::deserialize(&mut de) {
                 Err(DeError::TooManyEvents(count)) => assert_eq!(count.get(), 3),
-                e => panic!("Expected `Err(TooManyEvents(3))`, but found {:?}", e),
+                e => panic!("Expected `Err(TooManyEvents(3))`, but got `{:?}`", e),
             }
         }
 
@@ -3605,8 +3634,13 @@ mod tests {
             assert_eq!(de.peek().unwrap(), &Start(BytesStart::new("tag")));
 
             match de.read_to_end(QName(b"tag")) {
-                Err(DeError::UnexpectedEof) => (),
-                x => panic!("Expected `Err(UnexpectedEof)`, but found {:?}", x),
+                Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
+                    assert_eq!(cause, IllFormedError::MissedEnd("tag".into()))
+                }
+                x => panic!(
+                    "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
+                    x
+                ),
             }
             assert_eq!(de.next().unwrap(), Eof);
         }
@@ -3619,8 +3653,13 @@ mod tests {
             assert_eq!(de.peek().unwrap(), &Text("".into()));
 
             match de.read_to_end(QName(b"tag")) {
-                Err(DeError::UnexpectedEof) => (),
-                x => panic!("Expected `Err(UnexpectedEof)`, but found {:?}", x),
+                Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
+                    assert_eq!(cause, IllFormedError::MissedEnd("tag".into()))
+                }
+                x => panic!(
+                    "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
+                    x
+                ),
             }
             assert_eq!(de.next().unwrap(), Eof);
         }
@@ -3708,12 +3747,11 @@ mod tests {
     #[test]
     fn read_string() {
         match from_str::<String>(r#"</root>"#) {
-            Err(DeError::InvalidXml(Error::EndEventMismatch { expected, found })) => {
-                assert_eq!(expected, "");
-                assert_eq!(found, "root");
+            Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
+                assert_eq!(cause, IllFormedError::UnmatchedEnd("root".into()));
             }
             x => panic!(
-                r#"Expected `Err(InvalidXml(EndEventMismatch("", "root")))`, but found {:?}"#,
+                "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
                 x
             ),
         }
@@ -3722,14 +3760,14 @@ mod tests {
         assert_eq!(s, "");
 
         match from_str::<String>(r#"<root></other>"#) {
-            Err(DeError::InvalidXml(Error::EndEventMismatch { expected, found })) => {
-                assert_eq!(expected, "root");
-                assert_eq!(found, "other");
-            }
-            x => panic!(
-                r#"Expected `Err(InvalidXml(EndEventMismatch("root", "other")))`, but found {:?}"#,
-                x
+            Err(DeError::InvalidXml(Error::IllFormed(cause))) => assert_eq!(
+                cause,
+                IllFormedError::MismatchedEnd {
+                    expected: "root".into(),
+                    found: "other".into(),
+                }
             ),
+            x => panic!("Expected `Err(InvalidXml(IllFormed(_))`, but got `{:?}`", x),
         }
     }
 
@@ -4051,11 +4089,13 @@ mod tests {
                     assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
                     assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag")));
                     match de.next() {
-                        Err(DeError::InvalidXml(Error::EndEventMismatch { expected, found })) => {
-                            assert_eq!(expected, "");
-                            assert_eq!(found, "tag2");
+                        Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
+                            assert_eq!(cause, IllFormedError::UnmatchedEnd("tag2".into()));
                         }
-                        x => panic!("Expected `InvalidXml(EndEventMismatch {{ expected = '', found = 'tag2' }})`, but got {:?}", x),
+                        x => panic!(
+                            "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
+                            x
+                        ),
                     }
                     assert_eq!(de.next().unwrap(), DeEvent::Eof);
                 }
@@ -4192,11 +4232,13 @@ mod tests {
         fn end() {
             let mut de = make_de("</tag>");
             match de.next() {
-                Err(DeError::InvalidXml(Error::EndEventMismatch { expected, found })) => {
-                    assert_eq!(expected, "");
-                    assert_eq!(found, "tag");
+                Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
+                    assert_eq!(cause, IllFormedError::UnmatchedEnd("tag".into()));
                 }
-                x => panic!("Expected `InvalidXml(EndEventMismatch {{ expected = '', found = 'tag' }})`, but got {:?}", x),
+                x => panic!(
+                    "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
+                    x
+                ),
             }
             assert_eq!(de.next().unwrap(), DeEvent::Eof);
         }
@@ -4269,11 +4311,13 @@ mod tests {
                 // Text is trimmed from both sides
                 assert_eq!(de.next().unwrap(), DeEvent::Text("text".into()));
                 match de.next() {
-                    Err(DeError::InvalidXml(Error::EndEventMismatch { expected, found })) => {
-                        assert_eq!(expected, "");
-                        assert_eq!(found, "tag");
+                    Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
+                        assert_eq!(cause, IllFormedError::UnmatchedEnd("tag".into()));
                     }
-                    x => panic!("Expected `InvalidXml(EndEventMismatch {{ expected = '', found = 'tag' }})`, but got {:?}", x),
+                    x => panic!(
+                        "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
+                        x
+                    ),
                 }
                 assert_eq!(de.next().unwrap(), DeEvent::Eof);
             }
@@ -4299,11 +4343,13 @@ mod tests {
                     // Text is trimmed from the start
                     assert_eq!(de.next().unwrap(), DeEvent::Text("text  cdata ".into()));
                     match de.next() {
-                        Err(DeError::InvalidXml(Error::EndEventMismatch { expected, found })) => {
-                            assert_eq!(expected, "");
-                            assert_eq!(found, "tag");
+                        Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
+                            assert_eq!(cause, IllFormedError::UnmatchedEnd("tag".into()));
                         }
-                        x => panic!("Expected `InvalidXml(EndEventMismatch {{ expected = '', found = 'tag' }})`, but got {:?}", x),
+                        x => panic!(
+                            "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
+                            x
+                        ),
                     }
                     assert_eq!(de.next().unwrap(), DeEvent::Eof);
                 }
@@ -4403,11 +4449,13 @@ mod tests {
                 let mut de = make_de("<![CDATA[ cdata ]]></tag>");
                 assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
                 match de.next() {
-                    Err(DeError::InvalidXml(Error::EndEventMismatch { expected, found })) => {
-                        assert_eq!(expected, "");
-                        assert_eq!(found, "tag");
+                    Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
+                        assert_eq!(cause, IllFormedError::UnmatchedEnd("tag".into()));
                     }
-                    x => panic!("Expected `InvalidXml(EndEventMismatch {{ expected = '', found = 'tag' }})`, but got {:?}", x),
+                    x => panic!(
+                        "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
+                        x
+                    ),
                 }
                 assert_eq!(de.next().unwrap(), DeEvent::Eof);
             }
@@ -4431,11 +4479,13 @@ mod tests {
                     // Text is trimmed from the end
                     assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata  text".into()));
                     match de.next() {
-                        Err(DeError::InvalidXml(Error::EndEventMismatch { expected, found })) => {
-                            assert_eq!(expected, "");
-                            assert_eq!(found, "tag");
+                        Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
+                            assert_eq!(cause, IllFormedError::UnmatchedEnd("tag".into()));
                         }
-                        x => panic!("Expected `InvalidXml(EndEventMismatch {{ expected = '', found = 'tag' }})`, but got {:?}", x),
+                        x => panic!(
+                            "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
+                            x
+                        ),
                     }
                     assert_eq!(de.next().unwrap(), DeEvent::Eof);
                 }
@@ -4479,11 +4529,13 @@ mod tests {
                     let mut de = make_de("<![CDATA[ cdata ]]><![CDATA[ cdata2 ]]></tag>");
                     assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata  cdata2 ".into()));
                     match de.next() {
-                        Err(DeError::InvalidXml(Error::EndEventMismatch { expected, found })) => {
-                            assert_eq!(expected, "");
-                            assert_eq!(found, "tag");
+                        Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
+                            assert_eq!(cause, IllFormedError::UnmatchedEnd("tag".into()));
                         }
-                        x => panic!("Expected `InvalidXml(EndEventMismatch {{ expected = '', found = 'tag' }})`, but got {:?}", x),
+                        x => panic!(
+                            "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
+                            x
+                        ),
                     }
                     assert_eq!(de.next().unwrap(), DeEvent::Eof);
                 }
diff --git a/src/de/simple_type.rs b/src/de/simple_type.rs
index aa3be1e..10c3831 100644
--- a/src/de/simple_type.rs
+++ b/src/de/simple_type.rs
@@ -9,6 +9,7 @@ use crate::errors::serialize::DeError;
 use crate::escape::unescape;
 use crate::utils::CowRef;
 use memchr::memchr;
+use serde::de::value::UnitDeserializer;
 use serde::de::{DeserializeSeed, Deserializer, EnumAccess, SeqAccess, VariantAccess, Visitor};
 use serde::{self, serde_if_integer128};
 use std::borrow::Cow;
@@ -40,15 +41,17 @@ macro_rules! unsupported {
         $(
             ($($type:ty),*)
         )?
-        => $message:literal
     ) => {
         #[inline]
         fn $deserialize<V: Visitor<'de>>(
             self,
             $($(_: $type,)*)?
-            _visitor: V
+            visitor: V
         ) -> Result<V::Value, Self::Error> {
-            Err(DeError::Unsupported($message.into()))
+            // Deserializer methods are only hints, if deserializer could not satisfy
+            // request, it should return the data that it has. It is responsibility
+            // of a Visitor to return an error if it does not understand the data
+            self.deserialize_str(visitor)
         }
     };
 }
@@ -138,7 +141,8 @@ impl<'de, 'a> Content<'de, 'a> {
 ///
 /// Identifiers represented as strings and deserialized accordingly.
 ///
-/// Deserialization of all other types returns [`Unsupported`][DeError::Unsupported] error.
+/// Deserialization of all other types will provide a string and in most cases
+/// the deserialization will fail because visitor does not expect that.
 ///
 /// The `Owned` variant of the content acts as a storage for data, allocated by
 /// an external deserializer that pass it via [`ListIter`].
@@ -305,71 +309,68 @@ impl<'de, 'a> Deserializer<'de> for AtomicDeserializer<'de, 'a> {
         visitor.visit_unit()
     }
 
-    unsupported!(deserialize_bytes        => "byte arrays are not supported as `xs:list` items");
-    unsupported!(deserialize_byte_buf     => "byte arrays are not supported as `xs:list` items");
-    unsupported!(deserialize_seq          => "sequences are not supported as `xs:list` items");
-    unsupported!(deserialize_tuple(usize) => "tuples are not supported as `xs:list` items");
-    unsupported!(deserialize_tuple_struct(&'static str, usize) => "tuples are not supported as `xs:list` items");
-    unsupported!(deserialize_map          => "maps are not supported as `xs:list` items");
-    unsupported!(deserialize_struct(&'static str, &'static [&'static str]) => "structures are not supported as `xs:list` items");
+    unsupported!(deserialize_bytes);
+    unsupported!(deserialize_byte_buf);
+    unsupported!(deserialize_seq);
+    unsupported!(deserialize_tuple(usize));
+    unsupported!(deserialize_tuple_struct(&'static str, usize));
+    unsupported!(deserialize_map);
+    unsupported!(deserialize_struct(&'static str, &'static [&'static str]));
 }
 
 impl<'de, 'a> EnumAccess<'de> for AtomicDeserializer<'de, 'a> {
     type Error = DeError;
-    type Variant = AtomicUnitOnly;
+    type Variant = UnitOnly;
 
     fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), DeError>
     where
         V: DeserializeSeed<'de>,
     {
         let name = seed.deserialize(self)?;
-        Ok((name, AtomicUnitOnly))
+        Ok((name, UnitOnly))
     }
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 
 /// Deserializer of variant data, that supports only unit variants.
-/// Attempt to deserialize newtype, tuple or struct variant will return a
-/// [`DeError::Unsupported`] error.
-pub struct AtomicUnitOnly;
-impl<'de> VariantAccess<'de> for AtomicUnitOnly {
+/// Attempt to deserialize newtype will provide [`UnitDeserializer`].
+/// Attempt to deserialize tuple or struct variant will result to call of
+/// [`Visitor::visit_unit`].
+pub struct UnitOnly;
+impl<'de> VariantAccess<'de> for UnitOnly {
     type Error = DeError;
 
     #[inline]
-    fn unit_variant(self) -> Result<(), DeError> {
+    fn unit_variant(self) -> Result<(), Self::Error> {
         Ok(())
     }
 
-    fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, DeError>
+    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
     where
         T: DeserializeSeed<'de>,
     {
-        Err(DeError::Unsupported(
-            "enum newtype variants are not supported as `xs:list` items".into(),
-        ))
+        seed.deserialize(UnitDeserializer::<Self::Error>::new())
     }
 
-    fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, DeError>
+    #[inline]
+    fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
     where
         V: Visitor<'de>,
     {
-        Err(DeError::Unsupported(
-            "enum tuple variants are not supported as `xs:list` items".into(),
-        ))
+        visitor.visit_unit()
     }
 
+    #[inline]
     fn struct_variant<V>(
         self,
         _fields: &'static [&'static str],
-        _visitor: V,
-    ) -> Result<V::Value, DeError>
+        visitor: V,
+    ) -> Result<V::Value, Self::Error>
     where
         V: Visitor<'de>,
     {
-        Err(DeError::Unsupported(
-            "enum struct variants are not supported as `xs:list` items".into(),
-        ))
+        visitor.visit_unit()
     }
 }
 
@@ -498,10 +499,11 @@ impl<'de, 'a> SeqAccess<'de> for ListIter<'de, 'a> {
 /// - sequences, tuples and tuple structs are deserialized as `xs:list`s. Only
 ///   sequences of primitive types is possible to deserialize this way and they
 ///   should be delimited by a space (` `, `\t`, `\r`, or `\n`);
-/// - structs and maps returns [`DeError::Unsupported`];
+/// - structs and maps delegates to [`Self::deserialize_str`];
 /// - enums:
 ///   - unit variants: just return `()`;
-///   - all other variants returns [`DeError::Unsupported`];
+///   - newtype variants: deserialize from [`UnitDeserializer`];
+///   - tuple and struct variants: call [`Visitor::visit_unit`];
 /// - identifiers are deserialized as strings.
 ///
 /// [simple types]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
@@ -615,6 +617,7 @@ impl<'de, 'a> Deserializer<'de> for SimpleTypeDeserializer<'de, 'a> {
     deserialize_num!(deserialize_f64 => visit_f64);
 
     /// Forwards deserialization to the [`Self::deserialize_str`]
+    #[inline]
     fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
     where
         V: Visitor<'de>,
@@ -638,6 +641,7 @@ impl<'de, 'a> Deserializer<'de> for SimpleTypeDeserializer<'de, 'a> {
     }
 
     /// Forwards deserialization to the [`Self::deserialize_str`]
+    #[inline]
     fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
     where
         V: Visitor<'de>,
@@ -645,17 +649,17 @@ impl<'de, 'a> Deserializer<'de> for SimpleTypeDeserializer<'de, 'a> {
         self.deserialize_str(visitor)
     }
 
-    /// Returns [`DeError::Unsupported`]
-    fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
+    /// Forwards deserialization to the [`Self::deserialize_str`]
+    #[inline]
+    fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
     where
         V: Visitor<'de>,
     {
-        Err(DeError::Unsupported(
-            "binary data content is not supported by XML format".into(),
-        ))
+        self.deserialize_str(visitor)
     }
 
-    /// Forwards deserialization to the [`Self::deserialize_bytes`]
+    /// Forwards deserialization to the [`Self::deserialize_str`]
+    #[inline]
     fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
     where
         V: Visitor<'de>,
@@ -670,6 +674,7 @@ impl<'de, 'a> Deserializer<'de> for SimpleTypeDeserializer<'de, 'a> {
         visitor.visit_some(self)
     }
 
+    #[inline]
     fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
     where
         V: Visitor<'de>,
@@ -678,6 +683,7 @@ impl<'de, 'a> Deserializer<'de> for SimpleTypeDeserializer<'de, 'a> {
     }
 
     /// Forwards deserialization to the [`Self::deserialize_unit`]
+    #[inline]
     fn deserialize_unit_struct<V>(
         self,
         _name: &'static str,
@@ -711,6 +717,7 @@ impl<'de, 'a> Deserializer<'de> for SimpleTypeDeserializer<'de, 'a> {
     }
 
     /// Representation of tuples the same as [sequences][Self::deserialize_seq].
+    #[inline]
     fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
     where
         V: Visitor<'de>,
@@ -719,6 +726,7 @@ impl<'de, 'a> Deserializer<'de> for SimpleTypeDeserializer<'de, 'a> {
     }
 
     /// Representation of named tuples the same as [unnamed tuples][Self::deserialize_tuple].
+    #[inline]
     fn deserialize_tuple_struct<V>(
         self,
         _name: &'static str,
@@ -731,9 +739,8 @@ impl<'de, 'a> Deserializer<'de> for SimpleTypeDeserializer<'de, 'a> {
         self.deserialize_tuple(len, visitor)
     }
 
-    unsupported!(deserialize_map => "maps are not supported for XSD `simpleType`s");
-    unsupported!(deserialize_struct(&'static str, &'static [&'static str])
-                 => "structures are not supported for XSD `simpleType`s");
+    unsupported!(deserialize_map);
+    unsupported!(deserialize_struct(&'static str, &'static [&'static str]));
 
     fn deserialize_enum<V>(
         self,
@@ -748,6 +755,7 @@ impl<'de, 'a> Deserializer<'de> for SimpleTypeDeserializer<'de, 'a> {
     }
 
     /// Forwards deserialization to the [`Self::deserialize_str`]
+    #[inline]
     fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
     where
         V: Visitor<'de>,
@@ -755,6 +763,7 @@ impl<'de, 'a> Deserializer<'de> for SimpleTypeDeserializer<'de, 'a> {
         self.deserialize_str(visitor)
     }
 
+    #[inline]
     fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
     where
         V: Visitor<'de>,
@@ -765,60 +774,14 @@ impl<'de, 'a> Deserializer<'de> for SimpleTypeDeserializer<'de, 'a> {
 
 impl<'de, 'a> EnumAccess<'de> for SimpleTypeDeserializer<'de, 'a> {
     type Error = DeError;
-    type Variant = SimpleTypeUnitOnly;
+    type Variant = UnitOnly;
 
     fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), DeError>
     where
         V: DeserializeSeed<'de>,
     {
         let name = seed.deserialize(self)?;
-        Ok((name, SimpleTypeUnitOnly))
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/// Deserializer of variant data, that supports only unit variants.
-/// Attempt to deserialize newtype, tuple or struct variant will return a
-/// [`DeError::Unsupported`] error.
-pub struct SimpleTypeUnitOnly;
-impl<'de> VariantAccess<'de> for SimpleTypeUnitOnly {
-    type Error = DeError;
-
-    #[inline]
-    fn unit_variant(self) -> Result<(), DeError> {
-        Ok(())
-    }
-
-    fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, DeError>
-    where
-        T: DeserializeSeed<'de>,
-    {
-        Err(DeError::Unsupported(
-            "enum newtype variants are not supported for XSD `simpleType`s".into(),
-        ))
-    }
-
-    fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, DeError>
-    where
-        V: Visitor<'de>,
-    {
-        Err(DeError::Unsupported(
-            "enum tuple variants are not supported for XSD `simpleType`s".into(),
-        ))
-    }
-
-    fn struct_variant<V>(
-        self,
-        _fields: &'static [&'static str],
-        _visitor: V,
-    ) -> Result<V::Value, DeError>
-    where
-        V: Visitor<'de>,
-    {
-        Err(DeError::Unsupported(
-            "enum struct variants are not supported for XSD `simpleType`s".into(),
-        ))
+        Ok((name, UnitOnly))
     }
 }
 
@@ -886,7 +849,7 @@ mod tests {
                 match err {
                     DeError::$kind(e) => assert_eq!(e, $reason),
                     _ => panic!(
-                        "Expected `{}({})`, found `{:?}`",
+                        "Expected `Err({}({}))`, but got `{:?}`",
                         stringify!($kind),
                         $reason,
                         err
@@ -1004,7 +967,7 @@ mod tests {
                     match err {
                         DeError::$kind(e) => assert_eq!(e, $reason),
                         _ => panic!(
-                            "Expected `{}({})`, found `{:?}`",
+                            "Expected `Err({}({}))`, but got `{:?}`",
                             stringify!($kind),
                             $reason,
                             err
@@ -1046,9 +1009,9 @@ mod tests {
                 => Custom("invalid type: string \"escaped string\", expected a borrowed string"));
 
         err!(byte_buf: ByteBuf = "&lt;escaped&#32;string"
-                => Unsupported("byte arrays are not supported as `xs:list` items"));
+                => Custom("invalid type: string \"<escaped string\", expected byte data"));
         err!(borrowed_bytes: Bytes = "non-escaped string"
-                => Unsupported("byte arrays are not supported as `xs:list` items"));
+                => Custom("invalid type: string \"non-escaped string\", expected borrowed bytes"));
 
         deserialized_to!(option_none: Option<&str> = "" => None);
         deserialized_to!(option_some: Option<&str> = "non-escaped-string" => Some("non-escaped-string"));
@@ -1063,24 +1026,24 @@ mod tests {
                 => BorrowedNewtype("non-escaped string"));
 
         err!(seq: Vec<()> = "non-escaped string"
-                => Unsupported("sequences are not supported as `xs:list` items"));
+                => Custom("invalid type: string \"non-escaped string\", expected a sequence"));
         err!(tuple: ((), ()) = "non-escaped string"
-                => Unsupported("tuples are not supported as `xs:list` items"));
+                => Custom("invalid type: string \"non-escaped string\", expected a tuple of size 2"));
         err!(tuple_struct: Tuple = "non-escaped string"
-                => Unsupported("tuples are not supported as `xs:list` items"));
+                => Custom("invalid type: string \"non-escaped string\", expected tuple struct Tuple"));
 
         err!(map: HashMap<(), ()> = "non-escaped string"
-                => Unsupported("maps are not supported as `xs:list` items"));
+                => Custom("invalid type: string \"non-escaped string\", expected a map"));
         err!(struct_: Struct = "non-escaped string"
-                => Unsupported("structures are not supported as `xs:list` items"));
+                => Custom("invalid type: string \"non-escaped string\", expected struct Struct"));
 
         deserialized_to!(enum_unit: Enum = "Unit" => Enum::Unit);
         err!(enum_newtype: Enum = "Newtype"
-                => Unsupported("enum newtype variants are not supported as `xs:list` items"));
+                => Custom("invalid type: unit value, expected a string"));
         err!(enum_tuple: Enum = "Tuple"
-                => Unsupported("enum tuple variants are not supported as `xs:list` items"));
+                => Custom("invalid type: unit value, expected tuple variant Enum::Tuple"));
         err!(enum_struct: Enum = "Struct"
-                => Unsupported("enum struct variants are not supported as `xs:list` items"));
+                => Custom("invalid type: unit value, expected struct variant Enum::Struct"));
         err!(enum_other: Enum = "any data"
                 => Custom("unknown variant `any data`, expected one of `Unit`, `Newtype`, `Tuple`, `Struct`"));
 
@@ -1240,11 +1203,11 @@ mod tests {
 
         simple!(utf8, string: String = "&lt;escaped string" => "<escaped string");
         err!(utf8, byte_buf: ByteBuf = "&lt;escaped&#32;string"
-             => Unsupported("binary data content is not supported by XML format"));
+             => Custom("invalid type: string \"<escaped string\", expected byte data"));
 
         simple!(utf8, borrowed_str: &str = "non-escaped string" => "non-escaped string");
         err!(utf8, borrowed_bytes: Bytes = "&lt;escaped&#32;string"
-             => Unsupported("binary data content is not supported by XML format"));
+             => Custom("invalid type: string \"<escaped string\", expected borrowed bytes"));
 
         simple!(utf8, option_none: Option<&str> = "" => Some(""));
         simple!(utf8, option_some: Option<&str> = "non-escaped string" => Some("non-escaped string"));
@@ -1262,17 +1225,17 @@ mod tests {
             => BorrowedNewtype("non-escaped string"));
 
         err!(utf8, map: HashMap<(), ()> = "any data"
-             => Unsupported("maps are not supported for XSD `simpleType`s"));
+             => Custom("invalid type: string \"any data\", expected a map"));
         err!(utf8, struct_: Struct = "any data"
-             => Unsupported("structures are not supported for XSD `simpleType`s"));
+             => Custom("invalid type: string \"any data\", expected struct Struct"));
 
         simple!(utf8, enum_unit: Enum = "Unit" => Enum::Unit);
         err!(utf8, enum_newtype: Enum = "Newtype"
-             => Unsupported("enum newtype variants are not supported for XSD `simpleType`s"));
+             => Custom("invalid type: unit value, expected a string"));
         err!(utf8, enum_tuple: Enum = "Tuple"
-             => Unsupported("enum tuple variants are not supported for XSD `simpleType`s"));
+             => Custom("invalid type: unit value, expected tuple variant Enum::Tuple"));
         err!(utf8, enum_struct: Enum = "Struct"
-             => Unsupported("enum struct variants are not supported for XSD `simpleType`s"));
+             => Custom("invalid type: unit value, expected struct variant Enum::Struct"));
         err!(utf8, enum_other: Enum = "any data"
              => Custom("unknown variant `any data`, expected one of `Unit`, `Newtype`, `Tuple`, `Struct`"));
 
@@ -1301,7 +1264,7 @@ mod tests {
 
         macro_rules! unsupported {
             ($name:ident: $type:ty = $xml:literal => $err:literal) => {
-                err!(utf16, $name: $type = to_utf16($xml) => Unsupported($err));
+                err!(utf16, $name: $type = to_utf16($xml) => Custom($err));
             };
         }
 
@@ -1330,7 +1293,7 @@ mod tests {
 
         utf16!(string: String = "&lt;escaped&#32;string" => "<escaped string");
         unsupported!(borrowed_bytes: Bytes = "&lt;escaped&#32;string"
-                     => "binary data content is not supported by XML format");
+                    => "invalid type: string \"<escaped string\", expected borrowed bytes");
 
         utf16!(option_none: Option<()> = "" => Some(()));
         utf16!(option_some: Option<()> = "any data" => Some(()));
@@ -1341,23 +1304,23 @@ mod tests {
         utf16!(newtype_owned: Newtype = "&lt;escaped&#32;string" => Newtype("<escaped string".into()));
 
         // UTF-16 data never borrow because data was decoded not in-place
-        err!(utf16, newtype_borrowed: BorrowedNewtype = to_utf16("non-escaped string")
-             => Custom("invalid type: string \"non-escaped string\", expected a borrowed string"));
+        unsupported!(newtype_borrowed: BorrowedNewtype = "non-escaped string"
+                    => "invalid type: string \"non-escaped string\", expected a borrowed string");
 
         unsupported!(map: HashMap<(), ()> = "any data"
-                     => "maps are not supported for XSD `simpleType`s");
+                    => "invalid type: string \"any data\", expected a map");
         unsupported!(struct_: Struct = "any data"
-                     => "structures are not supported for XSD `simpleType`s");
+                    => "invalid type: string \"any data\", expected struct Struct");
 
         utf16!(enum_unit: Enum = "Unit" => Enum::Unit);
         unsupported!(enum_newtype: Enum = "Newtype"
-                     => "enum newtype variants are not supported for XSD `simpleType`s");
+                    => "invalid type: unit value, expected a string");
         unsupported!(enum_tuple: Enum = "Tuple"
-                     => "enum tuple variants are not supported for XSD `simpleType`s");
+                    => "invalid type: unit value, expected tuple variant Enum::Tuple");
         unsupported!(enum_struct: Enum = "Struct"
-                     => "enum struct variants are not supported for XSD `simpleType`s");
-        err!(utf16, enum_other: Enum = to_utf16("any data")
-             => Custom("unknown variant `any data`, expected one of `Unit`, `Newtype`, `Tuple`, `Struct`"));
+                    => "invalid type: unit value, expected struct variant Enum::Struct");
+        unsupported!(enum_other: Enum = "any data"
+                    => "unknown variant `any data`, expected one of `Unit`, `Newtype`, `Tuple`, `Struct`");
 
         utf16!(identifier: Id = "Field" => Id::Field);
         utf16!(ignored_any: Any = "any data" => Any(IgnoredAny));
diff --git a/src/de/text.rs b/src/de/text.rs
index 4c3b66d..f3129e4 100644
--- a/src/de/text.rs
+++ b/src/de/text.rs
@@ -32,7 +32,9 @@ use std::borrow::Cow;
 ///   deserializer;
 /// - sequences, tuples and tuple structs are deserialized using [`SimpleTypeDeserializer`]
 ///   (this is the difference): text content passed to the deserializer directly;
-/// - structs and maps returns [`DeError::ExpectedStart`];
+/// - structs and maps calls [`Visitor::visit_borrowed_str`] or [`Visitor::visit_string`],
+///   it is responsibility of the type to return an error if it do not able to process
+///   this data;
 /// - enums:
 ///   - the variant name is deserialized as `$text`;
 ///   - the content is deserialized using the same deserializer:
@@ -117,12 +119,15 @@ impl<'de> Deserializer<'de> for TextDeserializer<'de> {
         self,
         _name: &'static str,
         _fields: &'static [&'static str],
-        _visitor: V,
+        visitor: V,
     ) -> Result<V::Value, Self::Error>
     where
         V: Visitor<'de>,
     {
-        Err(DeError::ExpectedStart)
+        // Deserializer methods are only hints, if deserializer could not satisfy
+        // request, it should return the data that it has. It is responsibility
+        // of a Visitor to return an error if it does not understand the data
+        self.deserialize_str(visitor)
     }
 
     fn deserialize_enum<V>(
diff --git a/src/de/var.rs b/src/de/var.rs
index 1dc335c..f534283 100644
--- a/src/de/var.rs
+++ b/src/de/var.rs
@@ -50,7 +50,9 @@ where
                 seed.deserialize(BorrowedStrDeserializer::<DeError>::new(TEXT_KEY))?,
                 true,
             ),
-            DeEvent::End(e) => return Err(DeError::UnexpectedEnd(e.name().into_inner().to_vec())),
+            // SAFETY: The reader is guaranteed that we don't have unmatched tags
+            // If we here, then out deserializer has a bug
+            DeEvent::End(e) => unreachable!("{:?}", e),
             DeEvent::Eof => return Err(DeError::UnexpectedEof),
         };
         Ok((
diff --git a/src/errors.rs b/src/errors.rs
index 1b3a95c..0893edc 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -1,7 +1,9 @@
 //! Error management module
 
+use crate::encoding::Decoder;
 use crate::escape::EscapeError;
 use crate::events::attributes::AttrError;
+use crate::name::QName;
 use crate::utils::write_byte_string;
 use std::fmt;
 use std::io::Error as IoError;
@@ -9,6 +11,119 @@ use std::str::Utf8Error;
 use std::string::FromUtf8Error;
 use std::sync::Arc;
 
+/// An error returned if parsed document does not correspond to the XML grammar,
+/// for example, a tag opened by `<` not closed with `>`. This error does not
+/// represent invalid XML constructs, for example, tags `<>` and `</>` a well-formed
+/// from syntax point-of-view.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum SyntaxError {
+    /// The parser started to parse `<!`, but the input ended before it can recognize
+    /// anything.
+    InvalidBangMarkup,
+    /// The parser started to parse processing instruction or XML declaration (`<?`),
+    /// but the input ended before the `?>` sequence was found.
+    UnclosedPIOrXmlDecl,
+    /// The parser started to parse comment (`<!--`) content, but the input ended
+    /// before the `-->` sequence was found.
+    UnclosedComment,
+    /// The parser started to parse DTD (`<!DOCTYPE`) content, but the input ended
+    /// before the closing `>` character was found.
+    UnclosedDoctype,
+    /// The parser started to parse `<![CDATA[` content, but the input ended
+    /// before the `]]>` sequence was found.
+    UnclosedCData,
+    /// The parser started to parse tag content, but the input ended
+    /// before the closing `>` character was found.
+    UnclosedTag,
+}
+
+impl fmt::Display for SyntaxError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            Self::InvalidBangMarkup => f.write_str("unknown or missed symbol in markup"),
+            Self::UnclosedPIOrXmlDecl => {
+                f.write_str("processing instruction or xml declaration not closed: `?>` not found before end of input")
+            }
+            Self::UnclosedComment => {
+                f.write_str("comment not closed: `-->` not found before end of input")
+            }
+            Self::UnclosedDoctype => {
+                f.write_str("DOCTYPE not closed: `>` not found before end of input")
+            }
+            Self::UnclosedCData => {
+                f.write_str("CDATA not closed: `]]>` not found before end of input")
+            }
+            Self::UnclosedTag => f.write_str("tag not closed: `>` not found before end of input"),
+        }
+    }
+}
+
+impl std::error::Error for SyntaxError {}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/// An error returned if parsed document is not [well-formed], for example,
+/// an opened tag is not closed before end of input.
+///
+/// [well-formed]: https://www.w3.org/TR/xml11/#dt-wellformed
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum IllFormedError {
+    /// The end tag was not found during reading of a sub-tree of elements due to
+    /// encountering an EOF from the underlying reader. This error is returned from
+    /// [`Reader::read_to_end`].
+    ///
+    /// [`Reader::read_to_end`]: crate::reader::Reader::read_to_end
+    MissedEnd(String),
+    /// The specified end tag was encountered without corresponding open tag at the
+    /// same level of hierarchy
+    UnmatchedEnd(String),
+    /// The specified end tag does not match the start tag at that nesting level.
+    MismatchedEnd {
+        /// Name of open tag, that is expected to be closed
+        expected: String,
+        /// Name of actually closed tag
+        found: String,
+    },
+    /// A comment contains forbidden double-hyphen (`--`) sequence inside.
+    ///
+    /// According to the [specification], for compatibility, comments MUST NOT contain
+    /// double-hyphen (`--`) sequence, in particular, they cannot end by `--->`.
+    ///
+    /// The quick-xml by default does not check that, because this restriction is
+    /// mostly artificial, but you can enable it in the [configuration].
+    ///
+    /// [specification]: https://www.w3.org/TR/xml11/#sec-comments
+    /// [configuration]: crate::reader::Reader::check_comments
+    DoubleHyphenInComment,
+}
+
+impl fmt::Display for IllFormedError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            Self::MissedEnd(tag) => write!(
+                f,
+                "start tag not closed: `</{}>` not found before end of input",
+                tag,
+            ),
+            Self::UnmatchedEnd(tag) => {
+                write!(f, "close tag `</{}>` does not match any open tag", tag)
+            }
+            Self::MismatchedEnd { expected, found } => write!(
+                f,
+                "expected `</{}>`, but `</{}>` was found",
+                expected, found,
+            ),
+            Self::DoubleHyphenInComment => {
+                write!(f, "forbidden string `--` was found in a comment")
+            }
+        }
+    }
+}
+
+impl std::error::Error for IllFormedError {}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
 /// The error type used by this crate.
 #[derive(Clone, Debug)]
 pub enum Error {
@@ -16,32 +131,33 @@ pub enum Error {
     ///
     /// Contains the reference-counted I/O error to make the error type `Clone`able.
     Io(Arc<IoError>),
+    /// The document does not corresponds to the XML grammar.
+    Syntax(SyntaxError),
+    /// The document is not [well-formed](https://www.w3.org/TR/xml11/#dt-wellformed).
+    IllFormed(IllFormedError),
     /// Input decoding error. If [`encoding`] feature is disabled, contains `None`,
     /// otherwise contains the UTF-8 decoding error
     ///
     /// [`encoding`]: index.html#encoding
     NonDecodable(Option<Utf8Error>),
-    /// Unexpected End of File
-    UnexpectedEof(String),
-    /// End event mismatch
-    EndEventMismatch {
-        /// Expected end event
-        expected: String,
-        /// Found end event
-        found: String,
-    },
-    /// Unexpected token
-    UnexpectedToken(String),
-    /// Unexpected <!>
-    UnexpectedBang(u8),
-    /// Text not found, expected `Event::Text`
-    TextNotFound,
-    /// `Event::BytesDecl` must start with *version* attribute. Contains the attribute
-    /// that was found or `None` if an xml declaration doesn't contain attributes.
+    /// A `version` attribute was not found in an XML declaration or is not the
+    /// first attribute.
+    ///
+    /// According to the [specification], the XML declaration (`<?xml ?>`) MUST contain
+    /// a `version` attribute and it MUST be the first attribute. This error indicates,
+    /// that the declaration does not contain attributes at all (if contains `None`)
+    /// or either `version` attribute is not present or not the first attribute in
+    /// the declaration. In the last case it contains the name of the found attribute.
+    ///
+    /// [specification]: https://www.w3.org/TR/xml11/#sec-prolog-dtd
     XmlDeclWithoutVersion(Option<String>),
-    /// Empty `Event::DocType`. `<!doctype foo>` is correct but `<!doctype > is not.
+    /// A document type definition (DTD) does not contain a name of a root element.
     ///
-    /// See <https://www.w3.org/TR/xml11/#NT-doctypedecl>
+    /// According to the [specification], document type definition (`<!doctype foo>`)
+    /// MUST contain a name which defines a document type. If that name is missed,
+    /// this error is returned.
+    ///
+    /// [specification]: https://www.w3.org/TR/xml11/#NT-doctypedecl
     EmptyDocType,
     /// Attribute parsing error
     InvalidAttr(AttrError),
@@ -67,6 +183,15 @@ pub enum Error {
     },
 }
 
+impl Error {
+    pub(crate) fn missed_end(name: QName, decoder: Decoder) -> Self {
+        match decoder.decode(name.as_ref()) {
+            Ok(name) => IllFormedError::MissedEnd(name.into()).into(),
+            Err(err) => err.into(),
+        }
+    }
+}
+
 impl From<IoError> for Error {
     /// Creates a new `Error::Io` from the given error
     #[inline]
@@ -75,6 +200,22 @@ impl From<IoError> for Error {
     }
 }
 
+impl From<SyntaxError> for Error {
+    /// Creates a new `Error::Syntax` from the given error
+    #[inline]
+    fn from(error: SyntaxError) -> Self {
+        Self::Syntax(error)
+    }
+}
+
+impl From<IllFormedError> for Error {
+    /// Creates a new `Error::IllFormed` from the given error
+    #[inline]
+    fn from(error: IllFormedError) -> Self {
+        Self::IllFormed(error)
+    }
+}
+
 impl From<Utf8Error> for Error {
     /// Creates a new `Error::NonDecodable` from the given error
     #[inline]
@@ -113,25 +254,20 @@ impl fmt::Display for Error {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
             Error::Io(e) => write!(f, "I/O error: {}", e),
+            Error::Syntax(e) => write!(f, "syntax error: {}", e),
+            Error::IllFormed(e) => write!(f, "ill-formed document: {}", e),
             Error::NonDecodable(None) => write!(f, "Malformed input, decoding impossible"),
             Error::NonDecodable(Some(e)) => write!(f, "Malformed UTF-8 input: {}", e),
-            Error::UnexpectedEof(e) => write!(f, "Unexpected EOF during reading {}", e),
-            Error::EndEventMismatch { expected, found } => {
-                write!(f, "Expecting </{}> found </{}>", expected, found)
+            Error::XmlDeclWithoutVersion(None) => {
+                write!(f, "an XML declaration does not contain `version` attribute")
             }
-            Error::UnexpectedToken(e) => write!(f, "Unexpected token '{}'", e),
-            Error::UnexpectedBang(b) => write!(
-                f,
-                "Only Comment (`--`), CDATA (`[CDATA[`) and DOCTYPE (`DOCTYPE`) nodes can start with a '!', but symbol `{}` found",
-                *b as char
-            ),
-            Error::TextNotFound => write!(f, "Cannot read text, expecting Event::Text"),
-            Error::XmlDeclWithoutVersion(e) => write!(
+            Error::XmlDeclWithoutVersion(Some(attr)) => {
+                write!(f, "an XML declaration must start with `version` attribute, but in starts with `{}`", attr)
+            }
+            Error::EmptyDocType => write!(
                 f,
-                "XmlDecl must start with 'version' attribute, found {:?}",
-                e
+                "`<!DOCTYPE>` declaration does not contain a name of a document type"
             ),
-            Error::EmptyDocType => write!(f, "DOCTYPE declaration must not be empty"),
             Error::InvalidAttr(e) => write!(f, "error while parsing attribute: {}", e),
             Error::EscapeError(e) => write!(f, "{}", e),
             Error::UnknownPrefix(prefix) => {
@@ -154,6 +290,8 @@ impl std::error::Error for Error {
     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
         match self {
             Error::Io(e) => Some(e),
+            Error::Syntax(e) => Some(e),
+            Error::IllFormed(e) => Some(e),
             Error::NonDecodable(Some(e)) => Some(e),
             Error::InvalidAttr(e) => Some(e),
             Error::EscapeError(e) => Some(e),
@@ -196,14 +334,6 @@ pub mod serialize {
         /// not expecting. This happens when you try to deserialize a primitive
         /// value (numbers, strings, booleans) from an XML element.
         UnexpectedStart(Vec<u8>),
-        /// Deserializer encounter an end tag with a specified name when it is
-        /// not expecting. Usually that should not be possible, because XML reader
-        /// is not able to produce such stream of events that lead to this error.
-        ///
-        /// If you get this error this likely indicates and error in the `quick_xml`.
-        /// Please open an issue at <https://github.com/tafia/quick-xml>, provide
-        /// your Rust code and XML input.
-        UnexpectedEnd(Vec<u8>),
         /// The [`Reader`] produced [`Event::Eof`] when it is not expecting,
         /// for example, after producing [`Event::Start`] but before corresponding
         /// [`Event::End`].
@@ -213,12 +343,6 @@ pub mod serialize {
         /// [`Event::Start`]: crate::events::Event::Start
         /// [`Event::End`]: crate::events::Event::End
         UnexpectedEof,
-        /// This error indicates that [`deserialize_struct`] was called, but there
-        /// is no any XML element in the input. That means that you try to deserialize
-        /// a struct not from an XML element.
-        ///
-        /// [`deserialize_struct`]: serde::de::Deserializer::deserialize_struct
-        ExpectedStart,
         /// An attempt to deserialize to a type, that is not supported by the XML
         /// store at current position, for example, attempt to deserialize `struct`
         /// from attribute or attempt to deserialize binary data.
@@ -252,13 +376,7 @@ pub mod serialize {
                     write_byte_string(f, e)?;
                     f.write_str(")`")
                 }
-                DeError::UnexpectedEnd(e) => {
-                    f.write_str("Unexpected `Event::End(")?;
-                    write_byte_string(f, e)?;
-                    f.write_str(")`")
-                }
                 DeError::UnexpectedEof => write!(f, "Unexpected `Event::Eof`"),
-                DeError::ExpectedStart => write!(f, "Expecting `Event::Start`"),
                 DeError::Unsupported(s) => write!(f, "Unsupported operation: {}", s),
                 #[cfg(feature = "overlapped-lists")]
                 DeError::TooManyEvents(s) => write!(f, "Deserializer buffers {} events, limit exceeded", s),
diff --git a/src/lib.rs b/src/lib.rs
index 7b0c8d2..a44898c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -54,7 +54,7 @@
 #[cfg(feature = "serialize")]
 pub mod de;
 pub mod encoding;
-mod errors;
+pub mod errors;
 mod escapei;
 pub mod escape {
     //! Manage xml character escapes
diff --git a/src/name.rs b/src/name.rs
index a612868..7ac207c 100644
--- a/src/name.rs
+++ b/src/name.rs
@@ -931,7 +931,7 @@ mod namespaces {
                         assert_eq!(namespace, b"not_correct_namespace");
                     }
                     x => panic!(
-                        "Expected `Error::ReservedNamespaceError`, but found {:?}",
+                        "Expected `Err(InvalidPrefixBind {{ .. }})`, but got `{:?}`",
                         x
                     ),
                 }
@@ -949,7 +949,7 @@ mod namespaces {
                         assert_eq!(namespace, b"");
                     }
                     x => panic!(
-                        "Expected `Error::ReservedNamespaceError`, but found {:?}",
+                        "Expected `Err(InvalidPrefixBind {{ .. }})`, but got `{:?}`",
                         x
                     ),
                 }
@@ -970,7 +970,7 @@ mod namespaces {
                         assert_eq!(namespace, b"http://www.w3.org/XML/1998/namespace");
                     }
                     x => panic!(
-                        "Expected `Error::ReservedNamespaceError`, but found {:?}",
+                        "Expected `Err(InvalidPrefixBind {{ .. }})`, but got `{:?}`",
                         x
                     ),
                 }
@@ -1016,7 +1016,7 @@ mod namespaces {
                         assert_eq!(namespace, b"http://www.w3.org/2000/xmlns/");
                     }
                     x => panic!(
-                        "Expected `Error::ReservedNamespaceError`, but found {:?}",
+                        "Expected `Err(InvalidPrefixBind {{ .. }})`, but got `{:?}`",
                         x
                     ),
                 }
@@ -1037,7 +1037,7 @@ mod namespaces {
                         assert_eq!(namespace, b"not_correct_namespace");
                     }
                     x => panic!(
-                        "Expected `Error::ReservedNamespaceError`, but found {:?}",
+                        "Expected `Err(InvalidPrefixBind {{ .. }})`, but got `{:?}`",
                         x
                     ),
                 }
@@ -1055,7 +1055,7 @@ mod namespaces {
                         assert_eq!(namespace, b"");
                     }
                     x => panic!(
-                        "Expected `Error::ReservedNamespaceError`, but found {:?}",
+                        "Expected `Err(InvalidPrefixBind {{ .. }})`, but got `{:?}`",
                         x
                     ),
                 }
@@ -1076,7 +1076,7 @@ mod namespaces {
                         assert_eq!(namespace, b"http://www.w3.org/2000/xmlns/");
                     }
                     x => panic!(
-                        "Expected `Error::ReservedNamespaceError`, but found {:?}",
+                        "Expected `Err(InvalidPrefixBind {{ .. }})`, but got `{:?}`",
                         x
                     ),
                 }
diff --git a/src/reader/buffered_reader.rs b/src/reader/buffered_reader.rs
index a91eb18..d2089b7 100644
--- a/src/reader/buffered_reader.rs
+++ b/src/reader/buffered_reader.rs
@@ -316,7 +316,7 @@ impl<R: BufRead> Reader<R> {
     /// Manages nested cases where parent and child elements have the _literally_
     /// same name.
     ///
-    /// If corresponding [`End`] event will not be found, the [`Error::UnexpectedEof`]
+    /// If a corresponding [`End`] event is not found, an error of type [`Error::IllFormed`]
     /// will be returned. In particularly, that error will be returned if you call
     /// this method without consuming the corresponding [`Start`] event first.
     ///
diff --git a/src/reader/mod.rs b/src/reader/mod.rs
index b49c365..e7b9c37 100644
--- a/src/reader/mod.rs
+++ b/src/reader/mod.rs
@@ -5,7 +5,7 @@ use encoding_rs::Encoding;
 use std::ops::Range;
 
 use crate::encoding::Decoder;
-use crate::errors::{Error, Result};
+use crate::errors::{Error, Result, SyntaxError};
 use crate::events::Event;
 use crate::reader::state::ReaderState;
 
@@ -347,10 +347,7 @@ macro_rules! read_to_end {
                     }
                     depth -= 1;
                 }
-                Ok(Event::Eof) => {
-                    let name = $self.decoder().decode($end.as_ref());
-                    return Err(Error::UnexpectedEof(format!("</{:?}>", name)));
-                }
+                Ok(Event::Eof) => return Err(Error::missed_end($end, $self.decoder())),
                 _ => (),
             }
         }
@@ -809,8 +806,7 @@ impl BangType {
             Some(b'[') => Self::CData,
             Some(b'-') => Self::Comment,
             Some(b'D') | Some(b'd') => Self::DocType,
-            Some(b) => return Err(Error::UnexpectedBang(b)),
-            None => return Err(Error::UnexpectedEof("Bang".to_string())),
+            _ => return Err(Error::Syntax(SyntaxError::InvalidBangMarkup)),
         })
     }
 
@@ -877,12 +873,11 @@ impl BangType {
     }
     #[inline]
     fn to_err(&self) -> Error {
-        let bang_str = match self {
-            Self::CData => "CData",
-            Self::Comment => "Comment",
-            Self::DocType => "DOCTYPE",
-        };
-        Error::UnexpectedEof(bang_str.to_string())
+        match self {
+            Self::CData => Error::Syntax(SyntaxError::UnclosedCData),
+            Self::Comment => Error::Syntax(SyntaxError::UnclosedComment),
+            Self::DocType => Error::Syntax(SyntaxError::UnclosedDoctype),
+        }
     }
 }
 
@@ -1053,13 +1048,13 @@ mod test {
 
             mod read_bang_element {
                 use super::*;
+                use crate::errors::{Error, SyntaxError};
+                use crate::reader::BangType;
+                use crate::utils::Bytes;
 
                 /// Checks that reading CDATA content works correctly
                 mod cdata {
                     use super::*;
-                    use crate::errors::Error;
-                    use crate::reader::BangType;
-                    use crate::utils::Bytes;
                     use pretty_assertions::assert_eq;
 
                     /// Checks that if input begins like CDATA element, but CDATA start sequence
@@ -1073,10 +1068,9 @@ mod test {
                         //                ^= 0
 
                         match $source(&mut input).read_bang_element(buf, &mut position) $(.$await)? {
-                            Err(Error::UnexpectedEof(s)) if s == "CData" => {}
-                            x => assert!(
-                                false,
-                                r#"Expected `UnexpectedEof("CData")`, but result is: {:?}"#,
+                            Err(Error::Syntax(SyntaxError::UnclosedCData)) => {}
+                            x => panic!(
+                                "Expected `Err(Syntax(UnclosedCData))`, but got `{:?}`",
                                 x
                             ),
                         }
@@ -1093,10 +1087,9 @@ mod test {
                         //                ^= 0
 
                         match $source(&mut input).read_bang_element(buf, &mut position) $(.$await)? {
-                            Err(Error::UnexpectedEof(s)) if s == "CData" => {}
-                            x => assert!(
-                                false,
-                                r#"Expected `UnexpectedEof("CData")`, but result is: {:?}"#,
+                            Err(Error::Syntax(SyntaxError::UnclosedCData)) => {}
+                            x => panic!(
+                                "Expected `Err(Syntax(UnclosedCData))`, but got `{:?}`",
                                 x
                             ),
                         }
@@ -1162,9 +1155,6 @@ mod test {
                 /// [specification]: https://www.w3.org/TR/xml11/#dt-comment
                 mod comment {
                     use super::*;
-                    use crate::errors::Error;
-                    use crate::reader::BangType;
-                    use crate::utils::Bytes;
                     use pretty_assertions::assert_eq;
 
                     #[$test]
@@ -1176,10 +1166,9 @@ mod test {
                         //                ^= 0
 
                         match $source(&mut input).read_bang_element(buf, &mut position) $(.$await)? {
-                            Err(Error::UnexpectedEof(s)) if s == "Comment" => {}
-                            x => assert!(
-                                false,
-                                r#"Expected `UnexpectedEof("Comment")`, but result is: {:?}"#,
+                            Err(Error::Syntax(SyntaxError::UnclosedComment)) => {}
+                            x => panic!(
+                                "Expected `Err(Syntax(UnclosedComment))`, but got `{:?}`",
                                 x
                             ),
                         }
@@ -1194,10 +1183,9 @@ mod test {
                         //                ^= 0
 
                         match $source(&mut input).read_bang_element(buf, &mut position) $(.$await)? {
-                            Err(Error::UnexpectedEof(s)) if s == "Comment" => {}
-                            x => assert!(
-                                false,
-                                r#"Expected `UnexpectedEof("Comment")`, but result is: {:?}"#,
+                            Err(Error::Syntax(SyntaxError::UnclosedComment)) => {}
+                            x => panic!(
+                                "Expected `Err(Syntax(UnclosedComment))`, but got `{:?}`",
                                 x
                             ),
                         }
@@ -1212,10 +1200,9 @@ mod test {
                         //                ^= 0
 
                         match $source(&mut input).read_bang_element(buf, &mut position) $(.$await)? {
-                            Err(Error::UnexpectedEof(s)) if s == "Comment" => {}
-                            x => assert!(
-                                false,
-                                r#"Expected `UnexpectedEof("Comment")`, but result is: {:?}"#,
+                            Err(Error::Syntax(SyntaxError::UnclosedComment)) => {}
+                            x => panic!(
+                                "Expected `Err(Syntax(UnclosedComment))`, but got `{:?}`",
                                 x
                             ),
                         }
@@ -1230,10 +1217,9 @@ mod test {
                         //                ^= 0
 
                         match $source(&mut input).read_bang_element(buf, &mut position) $(.$await)? {
-                            Err(Error::UnexpectedEof(s)) if s == "Comment" => {}
-                            x => assert!(
-                                false,
-                                r#"Expected `UnexpectedEof("Comment")`, but result is: {:?}"#,
+                            Err(Error::Syntax(SyntaxError::UnclosedComment)) => {}
+                            x => panic!(
+                                "Expected `Err(Syntax(UnclosedComment))`, but got `{:?}`",
                                 x
                             ),
                         }
@@ -1248,10 +1234,9 @@ mod test {
                         //                ^= 0
 
                         match $source(&mut input).read_bang_element(buf, &mut position) $(.$await)? {
-                            Err(Error::UnexpectedEof(s)) if s == "Comment" => {}
-                            x => assert!(
-                                false,
-                                r#"Expected `UnexpectedEof("Comment")`, but result is: {:?}"#,
+                            Err(Error::Syntax(SyntaxError::UnclosedComment)) => {}
+                            x => panic!(
+                                "Expected `Err(Syntax(UnclosedComment))`, but got `{:?}`",
                                 x
                             ),
                         }
@@ -1301,9 +1286,6 @@ mod test {
 
                     mod uppercase {
                         use super::*;
-                        use crate::errors::Error;
-                        use crate::reader::BangType;
-                        use crate::utils::Bytes;
                         use pretty_assertions::assert_eq;
 
                         #[$test]
@@ -1314,10 +1296,9 @@ mod test {
                             //                ^= 0
 
                             match $source(&mut input).read_bang_element(buf, &mut position) $(.$await)? {
-                                Err(Error::UnexpectedEof(s)) if s == "DOCTYPE" => {}
-                                x => assert!(
-                                    false,
-                                    r#"Expected `UnexpectedEof("DOCTYPE")`, but result is: {:?}"#,
+                                Err(Error::Syntax(SyntaxError::UnclosedDoctype)) => {}
+                                x => panic!(
+                                    "Expected `Err(Syntax(UnclosedDoctype))`, but got `{:?}`",
                                     x
                                 ),
                             }
@@ -1332,10 +1313,9 @@ mod test {
                             //                ^= 0
 
                             match $source(&mut input).read_bang_element(buf, &mut position) $(.$await)? {
-                                Err(Error::UnexpectedEof(s)) if s == "DOCTYPE" => {}
-                                x => assert!(
-                                    false,
-                                    r#"Expected `UnexpectedEof("DOCTYPE")`, but result is: {:?}"#,
+                                Err(Error::Syntax(SyntaxError::UnclosedDoctype)) => {}
+                                x => panic!(
+                                    "Expected `Err(Syntax(UnclosedDoctype))`, but got `{:?}`",
                                     x
                                 ),
                             }
@@ -1368,10 +1348,9 @@ mod test {
                             //                ^= 0
 
                             match $source(&mut input).read_bang_element(buf, &mut position) $(.$await)? {
-                                Err(Error::UnexpectedEof(s)) if s == "DOCTYPE" => {}
-                                x => assert!(
-                                    false,
-                                    r#"Expected `UnexpectedEof("DOCTYPE")`, but result is: {:?}"#,
+                                Err(Error::Syntax(SyntaxError::UnclosedDoctype)) => {}
+                                x => panic!(
+                                    "Expected `Err(Syntax(UnclosedDoctype))`, but got `{:?}`",
                                     x
                                 ),
                             }
@@ -1381,9 +1360,6 @@ mod test {
 
                     mod lowercase {
                         use super::*;
-                        use crate::errors::Error;
-                        use crate::reader::BangType;
-                        use crate::utils::Bytes;
                         use pretty_assertions::assert_eq;
 
                         #[$test]
@@ -1394,10 +1370,9 @@ mod test {
                             //                ^= 0
 
                             match $source(&mut input).read_bang_element(buf, &mut position) $(.$await)? {
-                                Err(Error::UnexpectedEof(s)) if s == "DOCTYPE" => {}
-                                x => assert!(
-                                    false,
-                                    r#"Expected `UnexpectedEof("DOCTYPE")`, but result is: {:?}"#,
+                                Err(Error::Syntax(SyntaxError::UnclosedDoctype)) => {}
+                                x => panic!(
+                                    "Expected `Err(Syntax(UnclosedDoctype))`, but got `{:?}`",
                                     x
                                 ),
                             }
@@ -1412,10 +1387,9 @@ mod test {
                             //                ^= 0
 
                             match $source(&mut input).read_bang_element(buf, &mut position) $(.$await)? {
-                                Err(Error::UnexpectedEof(s)) if s == "DOCTYPE" => {}
-                                x => assert!(
-                                    false,
-                                    r#"Expected `UnexpectedEof("DOCTYPE")`, but result is: {:?}"#,
+                                Err(Error::Syntax(SyntaxError::UnclosedDoctype)) => {}
+                                x => panic!(
+                                    "Expected `Err(Syntax(UnclosedDoctype))`, but got `{:?}`",
                                     x
                                 ),
                             }
@@ -1448,10 +1422,9 @@ mod test {
                             //                ^= 0
 
                             match $source(&mut input).read_bang_element(buf, &mut position) $(.$await)? {
-                                Err(Error::UnexpectedEof(s)) if s == "DOCTYPE" => {}
-                                x => assert!(
-                                    false,
-                                    r#"Expected `UnexpectedEof("DOCTYPE")`, but result is: {:?}"#,
+                                Err(Error::Syntax(SyntaxError::UnclosedDoctype)) => {}
+                                x => panic!(
+                                    "Expected `Err(Syntax(UnclosedDoctype))`, but got `{:?}`",
                                     x
                                 ),
                             }
@@ -1635,7 +1608,7 @@ mod test {
             }
 
             mod issue_344 {
-                use crate::errors::Error;
+                use crate::errors::{Error, SyntaxError};
                 use crate::reader::Reader;
 
                 #[$test]
@@ -1643,10 +1616,9 @@ mod test {
                     let mut reader = Reader::from_str("![]]>");
 
                     match reader.$read_until_close($buf) $(.$await)? {
-                        Err(Error::UnexpectedEof(s)) if s == "CData" => {}
-                        x => assert!(
-                            false,
-                            r#"Expected `UnexpectedEof("CData")`, but result is: {:?}"#,
+                        Err(Error::Syntax(SyntaxError::UnclosedCData)) => {}
+                        x => panic!(
+                            "Expected `Err(Syntax(UnclosedCData))`, but got `{:?}`",
                             x
                         ),
                     }
@@ -1657,10 +1629,9 @@ mod test {
                     let mut reader = Reader::from_str("!- -->");
 
                     match reader.$read_until_close($buf) $(.$await)? {
-                        Err(Error::UnexpectedEof(s)) if s == "Comment" => {}
-                        x => assert!(
-                            false,
-                            r#"Expected `UnexpectedEof("Comment")`, but result is: {:?}"#,
+                        Err(Error::Syntax(SyntaxError::UnclosedComment)) => {}
+                        x => panic!(
+                            "Expected `Err(Syntax(UnclosedComment)`, but got `{:?}`",
                             x
                         ),
                     }
@@ -1671,10 +1642,9 @@ mod test {
                     let mut reader = Reader::from_str("!D>");
 
                     match reader.$read_until_close($buf) $(.$await)? {
-                        Err(Error::UnexpectedEof(s)) if s == "DOCTYPE" => {}
-                        x => assert!(
-                            false,
-                            r#"Expected `UnexpectedEof("DOCTYPE")`, but result is: {:?}"#,
+                        Err(Error::Syntax(SyntaxError::UnclosedDoctype)) => {}
+                        x => panic!(
+                            "Expected `Err(Syntax(UnclosedDoctype))`, but got `{:?}`",
                             x
                         ),
                     }
@@ -1685,10 +1655,9 @@ mod test {
                     let mut reader = Reader::from_str("!d>");
 
                     match reader.$read_until_close($buf) $(.$await)? {
-                        Err(Error::UnexpectedEof(s)) if s == "DOCTYPE" => {}
-                        x => assert!(
-                            false,
-                            r#"Expected `UnexpectedEof("DOCTYPE")`, but result is: {:?}"#,
+                        Err(Error::Syntax(SyntaxError::UnclosedDoctype)) => {}
+                        x => panic!(
+                            "Expected `Err(Syntax(UnclosedDoctype))`, but got `{:?}`",
                             x
                         ),
                     }
@@ -1771,22 +1740,15 @@ mod test {
                     );
                 }
 
+                /// Lone closing tags are not allowed, so testing it together with start tag
                 #[$test]
-                $($async)? fn start() {
-                    let mut reader = Reader::from_str("<tag>");
+                $($async)? fn start_and_end() {
+                    let mut reader = Reader::from_str("<tag></tag>");
 
                     assert_eq!(
                         reader.$read_event($buf) $(.$await)? .unwrap(),
                         Event::Start(BytesStart::new("tag"))
                     );
-                }
-
-                #[$test]
-                $($async)? fn end() {
-                    let mut reader = Reader::from_str("</tag>");
-                    // Because we expect invalid XML, do not check that
-                    // the end name paired with the start name
-                    reader.check_end_names(false);
 
                     assert_eq!(
                         reader.$read_event($buf) $(.$await)? .unwrap(),
diff --git a/src/reader/ns_reader.rs b/src/reader/ns_reader.rs
index 1c05faa..60d56a7 100644
--- a/src/reader/ns_reader.rs
+++ b/src/reader/ns_reader.rs
@@ -420,7 +420,7 @@ impl<R: BufRead> NsReader<R> {
     /// Manages nested cases where parent and child elements have the _literally_
     /// same name.
     ///
-    /// If corresponding [`End`] event will not be found, the [`UnexpectedEof`]
+    /// If a corresponding [`End`] event is not found, an error of type [`IllFormed`]
     /// will be returned. In particularly, that error will be returned if you call
     /// this method without consuming the corresponding [`Start`] event first.
     ///
@@ -501,7 +501,7 @@ impl<R: BufRead> NsReader<R> {
     ///
     /// [`Start`]: Event::Start
     /// [`End`]: Event::End
-    /// [`UnexpectedEof`]: crate::errors::Error::UnexpectedEof
+    /// [`IllFormed`]: crate::errors::Error::IllFormed
     /// [`read_to_end()`]: Self::read_to_end
     /// [`BytesStart::to_end()`]: crate::events::BytesStart::to_end
     /// [`expand_empty_elements`]: Self::expand_empty_elements
@@ -663,7 +663,7 @@ impl<'i> NsReader<&'i [u8]> {
     /// Manages nested cases where parent and child elements have the _literally_
     /// same name.
     ///
-    /// If corresponding [`End`] event will not be found, the [`UnexpectedEof`]
+    /// If a corresponding [`End`] event is not found, an error of type [`IllFormed`]
     /// will be returned. In particularly, that error will be returned if you call
     /// this method without consuming the corresponding [`Start`] event first.
     ///
@@ -738,7 +738,7 @@ impl<'i> NsReader<&'i [u8]> {
     ///
     /// [`Start`]: Event::Start
     /// [`End`]: Event::End
-    /// [`UnexpectedEof`]: crate::errors::Error::UnexpectedEof
+    /// [`IllFormed`]: crate::errors::Error::IllFormed
     /// [`BytesStart::to_end()`]: crate::events::BytesStart::to_end
     /// [`expand_empty_elements`]: Self::expand_empty_elements
     /// [the specification]: https://www.w3.org/TR/xml11/#dt-etag
diff --git a/src/reader/slice_reader.rs b/src/reader/slice_reader.rs
index aff8dcb..1cfdb36 100644
--- a/src/reader/slice_reader.rs
+++ b/src/reader/slice_reader.rs
@@ -9,7 +9,7 @@ use crate::reader::EncodingRef;
 #[cfg(feature = "encoding")]
 use encoding_rs::{Encoding, UTF_8};
 
-use crate::errors::{Error, Result};
+use crate::errors::{Error, Result, SyntaxError};
 use crate::events::Event;
 use crate::name::QName;
 use crate::reader::{is_whitespace, BangType, ReadElementState, Reader, Span, XmlSource};
@@ -84,7 +84,7 @@ impl<'a> Reader<&'a [u8]> {
     /// Manages nested cases where parent and child elements have the _literally_
     /// same name.
     ///
-    /// If corresponding [`End`] event will not be found, the [`Error::UnexpectedEof`]
+    /// If a corresponding [`End`] event is not found, an error of type [`Error::IllFormed`]
     /// will be returned. In particularly, that error will be returned if you call
     /// this method without consuming the corresponding [`Start`] event first.
     ///
@@ -318,9 +318,7 @@ impl<'a> XmlSource<'a, ()> for &'a [u8] {
 
         // Note: Do not update position, so the error points to a sane place
         // rather than at the EOF.
-        Err(Error::UnexpectedEof("Element".to_string()))
-
-        // FIXME: Figure out why the other one works without UnexpectedEof
+        Err(Error::Syntax(SyntaxError::UnclosedTag))
     }
 
     fn skip_whitespace(&mut self, position: &mut usize) -> Result<()> {
diff --git a/src/reader/state.rs b/src/reader/state.rs
index c145e19..6169cf6 100644
--- a/src/reader/state.rs
+++ b/src/reader/state.rs
@@ -2,7 +2,7 @@
 use encoding_rs::UTF_8;
 
 use crate::encoding::Decoder;
-use crate::errors::{Error, Result};
+use crate::errors::{Error, IllFormedError, Result, SyntaxError};
 use crate::events::{BytesCData, BytesDecl, BytesEnd, BytesStart, BytesText, Event};
 #[cfg(feature = "encoding")]
 use crate::reader::EncodingRef;
@@ -97,7 +97,7 @@ impl ReaderState {
                         .position(|p| buf[3 + p + 1] == b'-')
                     {
                         self.offset += len - p;
-                        return Err(Error::UnexpectedToken("--".to_string()));
+                        return Err(Error::IllFormed(IllFormedError::DoubleHyphenInComment));
                     }
                 }
                 Ok(Event::Comment(BytesText::wrap(
@@ -147,13 +147,6 @@ impl ReaderState {
         };
 
         let decoder = self.decoder();
-        let mismatch_err = |expected: String, found: &[u8], offset: &mut usize| {
-            *offset -= buf.len();
-            Err(Error::EndEventMismatch {
-                expected,
-                found: decoder.decode(found).unwrap_or_default().into_owned(),
-            })
-        };
 
         // Get the index in self.opened_buffer of the name of the last opened tag
         match self.opened_starts.pop() {
@@ -165,16 +158,25 @@ impl ReaderState {
                         // #513: In order to allow error recovery we should drop content of the buffer
                         self.opened_buffer.truncate(start);
 
-                        return mismatch_err(expected, name, &mut self.offset);
+                        // Report error at start of the end tag at `<` character
+                        // +2 for `<` and `>`
+                        self.offset -= buf.len() + 2;
+                        return Err(Error::IllFormed(IllFormedError::MismatchedEnd {
+                            expected,
+                            found: decoder.decode(name).unwrap_or_default().into_owned(),
+                        }));
                     }
                 }
 
                 self.opened_buffer.truncate(start);
             }
             None => {
-                if self.check_end_names {
-                    return mismatch_err("".to_string(), &buf[1..], &mut self.offset);
-                }
+                // Report error at start of the end tag at `<` character
+                // +2 for `<` and `>`
+                self.offset -= buf.len() + 2;
+                return Err(Error::IllFormed(IllFormedError::UnmatchedEnd(
+                    decoder.decode(name).unwrap_or_default().into_owned(),
+                )));
             }
         }
 
@@ -203,7 +205,7 @@ impl ReaderState {
             }
         } else {
             self.offset -= len;
-            Err(Error::UnexpectedEof("XmlDecl".to_string()))
+            Err(Error::Syntax(SyntaxError::UnclosedPIOrXmlDecl))
         }
     }
 
diff --git a/src/se/content.rs b/src/se/content.rs
index 984689f..91e0288 100644
--- a/src/se/content.rs
+++ b/src/se/content.rs
@@ -311,7 +311,7 @@ impl<'w, 'i, W: Write> Serializer for ContentSerializer<'w, 'i, W> {
 
     fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
         Err(DeError::Unsupported(
-            format!("serialization of map types is not supported in `$value` field").into(),
+            "serialization of map types is not supported in `$value` field".into(),
         ))
     }
 
@@ -575,7 +575,7 @@ pub(super) mod tests {
                     match $data.serialize(ser).unwrap_err() {
                         DeError::$kind(e) => assert_eq!(e, $reason),
                         e => panic!(
-                            "Expected `{}({})`, found `{:?}`",
+                            "Expected `Err({}({}))`, but got `{:?}`",
                             stringify!($kind),
                             $reason,
                             e
@@ -1015,7 +1015,7 @@ pub(super) mod tests {
                     match $data.serialize(ser).unwrap_err() {
                         DeError::$kind(e) => assert_eq!(e, $reason),
                         e => panic!(
-                            "Expected `{}({})`, found `{:?}`",
+                            "Expected `Err({}({}))`, but got `{:?}`",
                             stringify!($kind),
                             $reason,
                             e
diff --git a/src/se/element.rs b/src/se/element.rs
index afad2a9..3d6056e 100644
--- a/src/se/element.rs
+++ b/src/se/element.rs
@@ -645,7 +645,7 @@ mod tests {
                     match $data.serialize(ser).unwrap_err() {
                         DeError::$kind(e) => assert_eq!(e, $reason),
                         e => panic!(
-                            "Expected `{}({})`, found `{:?}`",
+                            "Expected `Err({}({}))`, but got `{:?}`",
                             stringify!($kind),
                             $reason,
                             e
@@ -1348,7 +1348,7 @@ mod tests {
                     match $data.serialize(ser).unwrap_err() {
                         DeError::$kind(e) => assert_eq!(e, $reason),
                         e => panic!(
-                            "Expected `{}({})`, found `{:?}`",
+                            "Expected `Err({}({}))`, but got `{:?}`",
                             stringify!($kind),
                             $reason,
                             e
diff --git a/src/se/key.rs b/src/se/key.rs
index f5f6e04..c260f4e 100644
--- a/src/se/key.rs
+++ b/src/se/key.rs
@@ -216,7 +216,7 @@ mod tests {
                 match $data.serialize(ser).unwrap_err() {
                     DeError::$kind(e) => assert_eq!(e, $reason),
                     e => panic!(
-                        "Expected `{}({})`, found `{:?}`",
+                        "Expected `Err({}({}))`, but got `{:?}`",
                         stringify!($kind),
                         $reason,
                         e
diff --git a/src/se/simple_type.rs b/src/se/simple_type.rs
index e396606..442af45 100644
--- a/src/se/simple_type.rs
+++ b/src/se/simple_type.rs
@@ -956,7 +956,7 @@ mod tests {
                     match $data.serialize(ser).unwrap_err() {
                         DeError::$kind(e) => assert_eq!(e, $reason),
                         e => panic!(
-                            "Expected `{}({})`, found `{:?}`",
+                            "Expected `Err({}({}))`, but got `{:?}`",
                             stringify!($kind),
                             $reason,
                             e
@@ -1074,7 +1074,7 @@ mod tests {
                     match $data.serialize(ser).unwrap_err() {
                         DeError::$kind(e) => assert_eq!(e, $reason),
                         e => panic!(
-                            "Expected `{}({})`, found `{:?}`",
+                            "Expected `Err({}({}))`, but got `{:?}`",
                             stringify!($kind),
                             $reason,
                             e


Test patch:
diff --git a/tests/issues.rs b/tests/issues.rs
index e6d5275..dc4103b 100644
--- a/tests/issues.rs
+++ b/tests/issues.rs
@@ -4,6 +4,7 @@
 
 use std::sync::mpsc;
 
+use quick_xml::errors::{IllFormedError, SyntaxError};
 use quick_xml::events::{BytesDecl, BytesStart, BytesText, Event};
 use quick_xml::name::QName;
 use quick_xml::reader::Reader;
@@ -144,14 +145,14 @@ mod issue514 {
         reader.check_end_names(true);
 
         match reader.read_event() {
-            Err(Error::EndEventMismatch { expected, found }) => {
-                assert_eq!(expected, "some-tag");
-                assert_eq!(found, "other-tag");
-            }
-            x => panic!(
-                r#"Expected `Err(EndEventMismatch("some-tag", "other-tag"))`, but found {:?}"#,
-                x
+            Err(Error::IllFormed(cause)) => assert_eq!(
+                cause,
+                IllFormedError::MismatchedEnd {
+                    expected: "some-tag".into(),
+                    found: "other-tag".into(),
+                }
             ),
+            x => panic!("Expected `Err(IllFormed(_))`, but got `{:?}`", x),
         }
         assert_eq!(reader.read_event().unwrap(), Event::Eof);
     }
@@ -172,11 +173,8 @@ mod issue604 {
             Event::Decl(BytesDecl::new("1.0", None, None))
         );
         match reader.read_event_into(&mut buf) {
-            Err(Error::UnexpectedEof(reason)) => assert_eq!(reason, "Comment"),
-            x => panic!(
-                r#"Expected `Err(UnexpectedEof("Comment"))`, but found {:?}"#,
-                x
-            ),
+            Err(Error::Syntax(SyntaxError::UnclosedComment)) => {}
+            x => panic!("Expected `Err(Syntax(UnclosedComment))`, but got `{:?}`", x),
         }
         assert_eq!(reader.read_event_into(&mut buf).unwrap(), Event::Eof);
     }
@@ -191,11 +189,8 @@ mod issue604 {
             Event::Decl(BytesDecl::new("1.0", None, None))
         );
         match reader.read_event_into(&mut buf) {
-            Err(Error::UnexpectedEof(reason)) => assert_eq!(reason, "Comment"),
-            x => panic!(
-                r#"Expected `Err(UnexpectedEof("Comment"))`, but found {:?}"#,
-                x
-            ),
+            Err(Error::Syntax(SyntaxError::UnclosedComment)) => {}
+            x => panic!("Expected `Err(Syntax(UnclosedComment))`, but got `{:?}`", x),
         }
         assert_eq!(reader.read_event_into(&mut buf).unwrap(), Event::Eof);
     }
diff --git a/tests/serde-de-enum.rs b/tests/serde-de-enum.rs
index 351f7cd..8202800 100644
--- a/tests/serde-de-enum.rs
+++ b/tests/serde-de-enum.rs
@@ -320,6 +320,7 @@ mod externally_tagged {
         /// Struct variant cannot be directly deserialized from `Text` / `CData` events
         mod struct_ {
             use super::*;
+            use pretty_assertions::assert_eq;
 
             #[derive(Debug, Deserialize, PartialEq)]
             enum Text {
@@ -330,24 +331,42 @@ mod externally_tagged {
             #[test]
             fn text() {
                 match from_str::<Text>(" text ") {
-                    Err(DeError::Unsupported(_)) => {}
-                    x => panic!("Expected `Err(Unsupported(_))`, but found {:?}", x),
+                    Err(DeError::Custom(reason)) => assert_eq!(
+                        reason,
+                        "invalid type: string \"text\", expected struct variant Text::Struct"
+                    ),
+                    x => panic!(
+                        r#"Expected `Err(Custom("invalid type: string \"text\", expected struct variant Text::Struct"))`, but got `{:?}`"#,
+                        x
+                    ),
                 }
             }
 
             #[test]
             fn cdata() {
                 match from_str::<Text>("<![CDATA[ cdata ]]>") {
-                    Err(DeError::Unsupported(_)) => {}
-                    x => panic!("Expected `Err(Unsupported(_))`, but found {:?}", x),
+                    Err(DeError::Custom(reason)) => assert_eq!(
+                        reason,
+                        "invalid type: string \" cdata \", expected struct variant Text::Struct"
+                    ),
+                    x => panic!(
+                        r#"Expected `Err(Custom("invalid type: string \" cdata \", expected struct variant Text::Struct"))`, but got `{:?}`"#,
+                        x
+                    ),
                 }
             }
 
             #[test]
             fn mixed() {
                 match from_str::<Text>(" te <![CDATA[ cdata ]]> xt ") {
-                    Err(DeError::Unsupported(_)) => {}
-                    x => panic!("Expected `Err(Unsupported(_))`, but found {:?}", x),
+                    Err(DeError::Custom(reason)) => assert_eq!(
+                        reason,
+                        "invalid type: string \"te  cdata  xt\", expected struct variant Text::Struct"
+                    ),
+                    x => panic!(
+                        r#"Expected `Err(Custom("invalid type: string \"te  cdata  xt\", expected struct variant Text::Struct"))`, but got `{:?}`"#,
+                        x
+                    ),
                 }
             }
         }
diff --git a/tests/serde-de-seq.rs b/tests/serde-de-seq.rs
index ced8298..24c5016 100644
--- a/tests/serde-de-seq.rs
+++ b/tests/serde-de-seq.rs
@@ -236,7 +236,7 @@ mod fixed_name {
                     assert_eq!(e, "invalid length 2, expected an array of length 3")
                 }
                 e => panic!(
-                    r#"Expected `Err(Custom("invalid length 2, expected an array of length 3"))`, but found {:?}"#,
+                    r#"Expected `Err(Custom("invalid length 2, expected an array of length 3"))`, but got `{:?}`"#,
                     e
                 ),
             }
@@ -262,7 +262,7 @@ mod fixed_name {
             match data {
                 Err(DeError::Custom(e)) => assert_eq!(e, "duplicate field `item`"),
                 e => panic!(
-                    r#"Expected `Err(Custom("duplicate field `item`"))`, but found {:?}"#,
+                    r#"Expected `Err(Custom("duplicate field `item`"))`, but got `{:?}`"#,
                     e
                 ),
             }
@@ -286,7 +286,7 @@ mod fixed_name {
             match data {
                 Err(DeError::Custom(e)) => assert_eq!(e, "missing field `item`"),
                 e => panic!(
-                    r#"Expected `Err(Custom("missing field `item`"))`, but found {:?}"#,
+                    r#"Expected `Err(Custom("missing field `item`"))`, but got `{:?}`"#,
                     e
                 ),
             }
@@ -352,7 +352,7 @@ mod fixed_name {
                         assert_eq!(e, "invalid length 1, expected an array of length 3")
                     }
                     e => panic!(
-                        r#"Expected Err(Custom("invalid length 1, expected an array of length 3")), got {:?}"#,
+                        r#"Expected `Err(Custom("invalid length 1, expected an array of length 3"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -386,7 +386,7 @@ mod fixed_name {
                         assert_eq!(e, "invalid length 1, expected an array of length 3")
                     }
                     e => panic!(
-                        r#"Expected Err(Custom("invalid length 1, expected an array of length 3")), got {:?}"#,
+                        r#"Expected `Err(Custom("invalid length 1, expected an array of length 3"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -460,7 +460,7 @@ mod fixed_name {
                         assert_eq!(e, "invalid length 1, expected an array of length 3")
                     }
                     e => panic!(
-                        r#"Expected Err(Custom("invalid length 1, expected an array of length 3")), got {:?}"#,
+                        r#"Expected `Err(Custom("invalid length 1, expected an array of length 3"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -495,7 +495,7 @@ mod fixed_name {
                         assert_eq!(e, "invalid length 1, expected an array of length 3")
                     }
                     e => panic!(
-                        r#"Expected Err(Custom("invalid length 1, expected an array of length 3")), got {:?}"#,
+                        r#"Expected `Err(Custom("invalid length 1, expected an array of length 3"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -569,7 +569,7 @@ mod fixed_name {
                         assert_eq!(e, "invalid length 1, expected an array of length 3")
                     }
                     e => panic!(
-                        r#"Expected Err(Custom("invalid length 1, expected an array of length 3")), got {:?}"#,
+                        r#"Expected `Err(Custom("invalid length 1, expected an array of length 3"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -604,7 +604,7 @@ mod fixed_name {
                         assert_eq!(e, "invalid length 1, expected an array of length 3")
                     }
                     e => panic!(
-                        r#"Expected Err(Custom("invalid length 1, expected an array of length 3")), got {:?}"#,
+                        r#"Expected `Err(Custom("invalid length 1, expected an array of length 3"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -663,7 +663,7 @@ mod fixed_name {
                         assert_eq!(e, "invalid length 1, expected an array of length 3")
                     }
                     e => panic!(
-                        r#"Expected Err(Custom("invalid length 1, expected an array of length 3")), got {:?}"#,
+                        r#"Expected `Err(Custom("invalid length 1, expected an array of length 3"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -699,7 +699,7 @@ mod fixed_name {
                         assert_eq!(e, "invalid length 1, expected an array of length 3")
                     }
                     e => panic!(
-                        r#"Expected Err(Custom("invalid length 1, expected an array of length 3")), got {:?}"#,
+                        r#"Expected `Err(Custom("invalid length 1, expected an array of length 3"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -1042,7 +1042,7 @@ mod fixed_name {
             match data {
                 Err(DeError::Custom(e)) => assert_eq!(e, "missing field `item`"),
                 e => panic!(
-                    r#"Expected `Err(Custom("missing field `item`"))`, but found {:?}"#,
+                    r#"Expected `Err(Custom("missing field `item`"))`, but got `{:?}`"#,
                     e
                 ),
             }
@@ -1124,7 +1124,7 @@ mod fixed_name {
                 match data {
                     Err(DeError::Custom(e)) => assert_eq!(e, "duplicate field `item`"),
                     e => panic!(
-                        r#"Expected Err(Custom("duplicate field `item`")), got {:?}"#,
+                        r#"Expected `Err(Custom("duplicate field `item`"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -1165,7 +1165,7 @@ mod fixed_name {
                 match data {
                     Err(DeError::Custom(e)) => assert_eq!(e, "duplicate field `outer`"),
                     e => panic!(
-                        r#"Expected Err(Custom("duplicate field `outer`")), got {:?}"#,
+                        r#"Expected `Err(Custom("duplicate field `outer`"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -1260,7 +1260,7 @@ mod fixed_name {
                         assert_eq!(e, "duplicate field `item`")
                     }
                     e => panic!(
-                        r#"Expected Err(Custom("duplicate field `item`")), got {:?}"#,
+                        r#"Expected `Err(Custom("duplicate field `item`"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -1303,7 +1303,7 @@ mod fixed_name {
                 match data {
                     Err(DeError::Custom(e)) => assert_eq!(e, "duplicate field `outer`"),
                     e => panic!(
-                        r#"Expected Err(Custom("duplicate field `outer`")), got {:?}"#,
+                        r#"Expected `Err(Custom("duplicate field `outer`"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -1398,7 +1398,7 @@ mod fixed_name {
                         assert_eq!(e, "duplicate field `item`")
                     }
                     e => panic!(
-                        r#"Expected Err(Custom("duplicate field `item`")), got {:?}"#,
+                        r#"Expected `Err(Custom("duplicate field `item`"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -1441,7 +1441,7 @@ mod fixed_name {
                 match data {
                     Err(DeError::Custom(e)) => assert_eq!(e, "duplicate field `outer`"),
                     e => panic!(
-                        r#"Expected Err(Custom("duplicate field `outer`")), got {:?}"#,
+                        r#"Expected `Err(Custom("duplicate field `outer`"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -1511,7 +1511,7 @@ mod fixed_name {
                 match data {
                     Err(DeError::Custom(e)) => assert_eq!(e, "duplicate field `item`"),
                     e => panic!(
-                        r#"Expected Err(Custom("duplicate field `item`")), got {:?}"#,
+                        r#"Expected `Err(Custom("duplicate field `item`"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -1553,7 +1553,7 @@ mod fixed_name {
                 match data {
                     Err(DeError::Custom(e)) => assert_eq!(e, "duplicate field `outer`"),
                     e => panic!(
-                        r#"Expected Err(Custom("duplicate field `outer`")), got {:?}"#,
+                        r#"Expected `Err(Custom("duplicate field `outer`"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -2128,7 +2128,7 @@ mod variable_name {
                         assert_eq!(e, "invalid length 1, expected an array of length 3")
                     }
                     e => panic!(
-                        r#"Expected Err(Custom("invalid length 1, expected an array of length 3")), got {:?}"#,
+                        r#"Expected `Err(Custom("invalid length 1, expected an array of length 3"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -2174,7 +2174,7 @@ mod variable_name {
                         assert_eq!(e, "invalid length 1, expected an array of length 3")
                     }
                     e => panic!(
-                        r#"Expected Err(Custom("invalid length 1, expected an array of length 3")), got {:?}"#,
+                        r#"Expected `Err(Custom("invalid length 1, expected an array of length 3"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -2270,7 +2270,7 @@ mod variable_name {
                         assert_eq!(e, "invalid length 1, expected an array of length 3")
                     }
                     e => panic!(
-                        r#"Expected Err(Custom("invalid length 1, expected an array of length 3")), got {:?}"#,
+                        r#"Expected `Err(Custom("invalid length 1, expected an array of length 3"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -2316,7 +2316,7 @@ mod variable_name {
                         assert_eq!(e, "invalid length 1, expected an array of length 3")
                     }
                     e => panic!(
-                        r#"Expected Err(Custom("invalid length 1, expected an array of length 3")), got {:?}"#,
+                        r#"Expected `Err(Custom("invalid length 1, expected an array of length 3"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -2435,7 +2435,7 @@ mod variable_name {
                                 assert_eq!(e, "invalid length 1, expected an array of length 2")
                             }
                             e => panic!(
-                                r#"Expected Err(Custom("invalid length 1, expected an array of length 2")), got {:?}"#,
+                                r#"Expected `Err(Custom("invalid length 1, expected an array of length 2"))`, but got `{:?}`"#,
                                 e
                             ),
                         }
@@ -2472,7 +2472,7 @@ mod variable_name {
                                 assert_eq!(e, "invalid length 1, expected an array of length 3")
                             }
                             e => panic!(
-                                r#"Expected Err(Custom("invalid length 1, expected an array of length 3")), got {:?}"#,
+                                r#"Expected `Err(Custom("invalid length 1, expected an array of length 3"))`, but got `{:?}`"#,
                                 e
                             ),
                         }
@@ -2512,7 +2512,7 @@ mod variable_name {
                                 assert_eq!(e, "invalid length 1, expected an array of length 2")
                             }
                             e => panic!(
-                                r#"Expected Err(Custom("invalid length 1, expected an array of length 2")), got {:?}"#,
+                                r#"Expected `Err(Custom("invalid length 1, expected an array of length 2"))`, but got `{:?}`"#,
                                 e
                             ),
                         }
@@ -2552,7 +2552,7 @@ mod variable_name {
                                 assert_eq!(e, "invalid length 1, expected an array of length 3")
                             }
                             e => panic!(
-                                r#"Expected Err(Custom("invalid length 1, expected an array of length 3")), got {:?}"#,
+                                r#"Expected `Err(Custom("invalid length 1, expected an array of length 3"))`, but got `{:?}`"#,
                                 e
                             ),
                         }
@@ -2667,7 +2667,7 @@ mod variable_name {
                                 assert_eq!(e, "invalid length 1, expected an array of length 2")
                             }
                             e => panic!(
-                                r#"Expected Err(Custom("invalid length 1, expected an array of length 2")), got {:?}"#,
+                                r#"Expected `Err(Custom("invalid length 1, expected an array of length 2"))`, but got `{:?}`"#,
                                 e
                             ),
                         }
@@ -2704,7 +2704,7 @@ mod variable_name {
                                 assert_eq!(e, "invalid length 1, expected an array of length 3")
                             }
                             e => panic!(
-                                r#"Expected Err(Custom("invalid length 1, expected an array of length 3")), got {:?}"#,
+                                r#"Expected `Err(Custom("invalid length 1, expected an array of length 3"))`, but got `{:?}`"#,
                                 e
                             ),
                         }
@@ -2744,7 +2744,7 @@ mod variable_name {
                                 assert_eq!(e, "invalid length 1, expected an array of length 2")
                             }
                             e => panic!(
-                                r#"Expected Err(Custom("invalid length 1, expected an array of length 2")), got {:?}"#,
+                                r#"Expected `Err(Custom("invalid length 1, expected an array of length 2"))`, but got `{:?}`"#,
                                 e
                             ),
                         }
@@ -2784,7 +2784,7 @@ mod variable_name {
                                 assert_eq!(e, "invalid length 1, expected an array of length 3")
                             }
                             e => panic!(
-                                r#"Expected Err(Custom("invalid length 1, expected an array of length 3")), got {:?}"#,
+                                r#"Expected `Err(Custom("invalid length 1, expected an array of length 3"))`, but got `{:?}`"#,
                                 e
                             ),
                         }
@@ -2863,7 +2863,7 @@ mod variable_name {
                             assert_eq!(e, "invalid length 1, expected an array of length 3")
                         }
                         e => panic!(
-                            r#"Expected Err(Custom("invalid length 1, expected an array of length 3")), got {:?}"#,
+                            r#"Expected `Err(Custom("invalid length 1, expected an array of length 3"))`, but got `{:?}`"#,
                             e
                         ),
                     }
@@ -3270,7 +3270,7 @@ mod variable_name {
                 match data {
                     Err(DeError::Custom(e)) => assert_eq!(e, "duplicate field `$value`"),
                     e => panic!(
-                        r#"Expected Err(Custom("duplicate field `$value`")), got {:?}"#,
+                        r#"Expected `Err(Custom("duplicate field `$value`"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -3316,7 +3316,7 @@ mod variable_name {
                         assert_eq!(e, "duplicate field `$value`")
                     }
                     e => panic!(
-                        r#"Expected Err(Custom("duplicate field `$value`")), got {:?}"#,
+                        r#"Expected `Err(Custom("duplicate field `$value`"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -3410,7 +3410,7 @@ mod variable_name {
                 match data {
                     Err(DeError::Custom(e)) => assert_eq!(e, "duplicate field `$value`"),
                     e => panic!(
-                        r#"Expected Err(Custom("duplicate field `$value`")), got {:?}"#,
+                        r#"Expected `Err(Custom("duplicate field `$value`"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -3456,7 +3456,7 @@ mod variable_name {
                         assert_eq!(e, "duplicate field `$value`")
                     }
                     e => panic!(
-                        r#"Expected Err(Custom("duplicate field `$value`")), got {:?}"#,
+                        r#"Expected `Err(Custom("duplicate field `$value`"))`, but got `{:?}`"#,
                         e
                     ),
                 }
@@ -3575,7 +3575,7 @@ mod variable_name {
                                 assert_eq!(e, "duplicate field `element`")
                             }
                             e => panic!(
-                                r#"Expected Err(Custom("duplicate field `element`")), got {:?}"#,
+                                r#"Expected `Err(Custom("duplicate field `element`"))`, but got `{:?}`"#,
                                 e
                             ),
                         }
@@ -3612,7 +3612,7 @@ mod variable_name {
                                 assert_eq!(e, "duplicate field `$value`")
                             }
                             e => panic!(
-                                r#"Expected Err(Custom("duplicate field `$value`")), got {:?}"#,
+                                r#"Expected `Err(Custom("duplicate field `$value`"))`, but got `{:?}`"#,
                                 e
                             ),
                         }
@@ -3652,7 +3652,7 @@ mod variable_name {
                                 assert_eq!(e, "duplicate field `element`")
                             }
                             e => panic!(
-                                r#"Expected Err(Custom("duplicate field `element`")), got {:?}"#,
+                                r#"Expected `Err(Custom("duplicate field `element`"))`, but got `{:?}`"#,
                                 e
                             ),
                         }
@@ -3692,7 +3692,7 @@ mod variable_name {
                                 assert_eq!(e, "duplicate field `$value`")
                             }
                             e => panic!(
-                                r#"Expected Err(Custom("duplicate field `$value`")), got {:?}"#,
+                                r#"Expected `Err(Custom("duplicate field `$value`"))`, but got `{:?}`"#,
                                 e
                             ),
                         }
@@ -3807,7 +3807,7 @@ mod variable_name {
                                 assert_eq!(e, "duplicate field `element`")
                             }
                             e => panic!(
-                                r#"Expected Err(Custom("duplicate field `element`")), got {:?}"#,
+                                r#"Expected `Err(Custom("duplicate field `element`"))`, but got `{:?}`"#,
                                 e
                             ),
                         }
@@ -3844,7 +3844,7 @@ mod variable_name {
                                 assert_eq!(e, "duplicate field `$value`")
                             }
                             e => panic!(
-                                r#"Expected Err(Custom("duplicate field `$value`")), got {:?}"#,
+                                r#"Expected `Err(Custom("duplicate field `$value`"))`, but got `{:?}`"#,
                                 e
                             ),
                         }
@@ -3884,7 +3884,7 @@ mod variable_name {
                                 assert_eq!(e, "duplicate field `element`")
                             }
                             e => panic!(
-                                r#"Expected Err(Custom("duplicate field `element`")), got {:?}"#,
+                                r#"Expected `Err(Custom("duplicate field `element`"))`, but got `{:?}`"#,
                                 e
                             ),
                         }
@@ -3924,7 +3924,7 @@ mod variable_name {
                                 assert_eq!(e, "duplicate field `$value`")
                             }
                             e => panic!(
-                                r#"Expected Err(Custom("duplicate field `$value`")), got {:?}"#,
+                                r#"Expected `Err(Custom("duplicate field `$value`"))`, but got `{:?}`"#,
                                 e
                             ),
                         }
@@ -4003,7 +4003,7 @@ mod variable_name {
                             assert_eq!(e, "invalid length 1, expected an array of length 3")
                         }
                         e => panic!(
-                            r#"Expected Err(Custom("invalid length 1, expected an array of length 3")), got {:?}"#,
+                            r#"Expected `Err(Custom("invalid length 1, expected an array of length 3"))`, but got `{:?}`"#,
                             e
                         ),
                     }
diff --git a/tests/serde-de.rs b/tests/serde-de.rs
index b20d906..1aa00c9 100644
--- a/tests/serde-de.rs
+++ b/tests/serde-de.rs
@@ -70,7 +70,7 @@ fn ignored_any() {
     let err = from_str::<IgnoredAny>("");
     match err {
         Err(DeError::UnexpectedEof) => {}
-        other => panic!("Expected `UnexpectedEof`, found {:?}", other),
+        x => panic!("Expected `Err(UnexpectedEof)`, but got `{:?}`", x),
     }
 
     from_str::<IgnoredAny>(r#"<empty/>"#).unwrap();
@@ -91,9 +91,9 @@ mod trivial {
             #[test]
             fn $name() {
                 match from_str::<$type>($value) {
-                    Err(DeError::UnexpectedEof) => (),
+                    Err(DeError::UnexpectedEof) => {}
                     x => panic!(
-                        r#"Expected `Err(DeError::UnexpectedEof)`, but got `{:?}`"#,
+                        r#"Expected `Err(UnexpectedEof)`, but got `{:?}`"#,
                         x
                     ),
                 }
@@ -130,11 +130,9 @@ mod trivial {
             #[test]
             fn byte_buf() {
                 match from_str::<ByteBuf>($value) {
-                    Err(DeError::Unsupported(msg)) => {
-                        assert_eq!(msg, "binary data content is not supported by XML format")
-                    }
+                    Err(DeError::UnexpectedEof) => {}
                     x => panic!(
-                        r#"Expected `Err(DeError::Unsupported("binary data content is not supported by XML format"))`, but got `{:?}`"#,
+                        r#"Expected `Err(UnexpectedEof)`, but got `{:?}`"#,
                         x
                     ),
                 }
@@ -144,11 +142,9 @@ mod trivial {
             #[test]
             fn bytes() {
                 match from_str::<Bytes>($value) {
-                    Err(DeError::Unsupported(msg)) => {
-                        assert_eq!(msg, "binary data content is not supported by XML format")
-                    }
+                    Err(DeError::UnexpectedEof) => {}
                     x => panic!(
-                        r#"Expected `Err(DeError::Unsupported("binary data content is not supported by XML format"))`, but got `{:?}`"#,
+                        r#"Expected `Err(UnexpectedEof)`, but got `{:?}`"#,
                         x
                     ),
                 }
@@ -157,9 +153,9 @@ mod trivial {
             #[test]
             fn unit() {
                 match from_str::<()>($value) {
-                    Err(DeError::UnexpectedEof) => (),
+                    Err(DeError::UnexpectedEof) => {}
                     x => panic!(
-                        r#"Expected `Err(DeError::UnexpectedEof)`, but got `{:?}`"#,
+                        r#"Expected `Err(UnexpectedEof)`, but got `{:?}`"#,
                         x
                     ),
                 }
@@ -170,7 +166,6 @@ mod trivial {
     /// Empty document should considered invalid no matter what type we try to deserialize
     mod empty_doc {
         use super::*;
-        use pretty_assertions::assert_eq;
 
         eof!("");
     }
@@ -178,7 +173,6 @@ mod trivial {
     /// Document that contains only comment should be handled as if it is empty
     mod only_comment {
         use super::*;
-        use pretty_assertions::assert_eq;
 
         eof!("<!--comment-->");
     }
@@ -199,7 +193,7 @@ mod trivial {
                         // Expected unexpected start element `<nested>`
                         Err(DeError::UnexpectedStart(tag)) => assert_eq!(tag, b"nested"),
                         x => panic!(
-                            r#"Expected `Err(DeError::UnexpectedStart("nested"))`, but got `{:?}`"#,
+                            r#"Expected `Err(UnexpectedStart("nested"))`, but got `{:?}`"#,
                             x
                         ),
                     }
@@ -208,7 +202,7 @@ mod trivial {
                         // Expected unexpected start element `<something-else>`
                         Err(DeError::UnexpectedStart(tag)) => assert_eq!(tag, b"something-else"),
                         x => panic!(
-                            r#"Expected `Err(DeError::UnexpectedStart("something-else"))`, but got `{:?}`"#,
+                            r#"Expected `Err(UnexpectedStart("something-else"))`, but got `{:?}`"#,
                             x
                         ),
                     }
@@ -217,7 +211,7 @@ mod trivial {
                         // Expected unexpected start element `<something-else>`
                         Err(DeError::UnexpectedStart(tag)) => assert_eq!(tag, b"something-else"),
                         x => panic!(
-                            r#"Expected `Err(DeError::UnexpectedStart("something-else"))`, but got `{:?}`"#,
+                            r#"Expected `Err(UnexpectedStart("something-else"))`, but got `{:?}`"#,
                             x
                         ),
                     }
@@ -225,32 +219,42 @@ mod trivial {
 
                 #[test]
                 fn field() {
-                    let item: Field<$type> = from_str(&format!("<root><value>{}</value></root>", $value)).unwrap();
+                    let item: Field<$type> =
+                        from_str(&format!("<root><value>{}</value></root>", $value)).unwrap();
                     assert_eq!(item, Field { value: $expected });
 
-                    match from_str::<Field<$type>>(&format!("<root><value><nested>{}</nested></value></root>", $value)) {
+                    match from_str::<Field<$type>>(&format!(
+                        "<root><value><nested>{}</nested></value></root>",
+                        $value
+                    )) {
                         // Expected unexpected start element `<nested>`
                         Err(DeError::UnexpectedStart(tag)) => assert_eq!(tag, b"nested"),
                         x => panic!(
-                            r#"Expected `Err(DeError::UnexpectedStart("nested"))`, but got `{:?}`"#,
+                            r#"Expected `Err(UnexpectedStart("nested"))`, but got `{:?}`"#,
                             x
                         ),
                     }
 
-                    match from_str::<Field<$type>>(&format!("<root><value>{}<something-else/></value></root>", $value)) {
+                    match from_str::<Field<$type>>(&format!(
+                        "<root><value>{}<something-else/></value></root>",
+                        $value
+                    )) {
                         // Expected unexpected start element `<something-else>`
                         Err(DeError::UnexpectedStart(tag)) => assert_eq!(tag, b"something-else"),
                         x => panic!(
-                            r#"Expected `Err(DeError::UnexpectedStart("something-else"))`, but got `{:?}`"#,
+                            r#"Expected `Err(UnexpectedStart("something-else"))`, but got `{:?}`"#,
                             x
                         ),
                     }
 
-                    match from_str::<Field<$type>>(&format!("<root><value><something-else/>{}</value></root>", $value)) {
+                    match from_str::<Field<$type>>(&format!(
+                        "<root><value><something-else/>{}</value></root>",
+                        $value
+                    )) {
                         // Expected unexpected start element `<something-else>`
                         Err(DeError::UnexpectedStart(tag)) => assert_eq!(tag, b"something-else"),
                         x => panic!(
-                            r#"Expected `Err(DeError::UnexpectedStart("something-else"))`, but got `{:?}`"#,
+                            r#"Expected `Err(UnexpectedStart("something-else"))`, but got `{:?}`"#,
                             x
                         ),
                     }
@@ -259,24 +263,30 @@ mod trivial {
                 /// Tests deserialization from top-level tag content: `<root>...content...</root>`
                 #[test]
                 fn text() {
-                    let item: Trivial<$type> = from_str(&format!("<root>{}</root>", $value)).unwrap();
+                    let item: Trivial<$type> =
+                        from_str(&format!("<root>{}</root>", $value)).unwrap();
                     assert_eq!(item, Trivial { value: $expected });
 
                     // Unlike `naked` test, here we have a struct that is serialized to XML with
                     // an implicit field `$text` and some other field "something-else" which not interested
                     // for us in the Trivial structure. If you want the same behavior as for naked primitive,
                     // use `$value` field which would consume all data, unless a dedicated field would present
-                    let item: Trivial<$type> = from_str(&format!("<root>{}<something-else/></root>", $value)).unwrap();
+                    let item: Trivial<$type> =
+                        from_str(&format!("<root>{}<something-else/></root>", $value)).unwrap();
                     assert_eq!(item, Trivial { value: $expected });
 
-                    let item: Trivial<$type> = from_str(&format!("<root><something-else/>{}</root>", $value)).unwrap();
+                    let item: Trivial<$type> =
+                        from_str(&format!("<root><something-else/>{}</root>", $value)).unwrap();
                     assert_eq!(item, Trivial { value: $expected });
 
-                    match from_str::<Trivial<$type>>(&format!("<root><nested>{}</nested></root>", $value)) {
+                    match from_str::<Trivial<$type>>(&format!(
+                        "<root><nested>{}</nested></root>",
+                        $value
+                    )) {
                         // Expected unexpected start element `<nested>`
                         Err(DeError::Custom(reason)) => assert_eq!(reason, "missing field `$text`"),
                         x => panic!(
-                            r#"Expected `Err(DeError::Custom("missing field `$text`"))`, but got `{:?}`"#,
+                            r#"Expected `Err(Custom("missing field `$text`"))`, but got `{:?}`"#,
                             x
                         ),
                     }
@@ -338,11 +348,11 @@ mod trivial {
         #[test]
         fn byte_buf() {
             match from_str::<Trivial<ByteBuf>>("<root>escaped&#x20;byte_buf</root>") {
-                Err(DeError::Unsupported(msg)) => {
-                    assert_eq!(msg, "binary data content is not supported by XML format")
+                Err(DeError::Custom(msg)) => {
+                    assert_eq!(msg, "invalid type: string \"escaped byte_buf\", expected byte data")
                 }
                 x => panic!(
-                    r#"Expected `Err(DeError::Unsupported("binary data content is not supported by XML format"))`, but got `{:?}`"#,
+                    r#"Expected `Err(Custom("invalid type: string \"escaped byte_buf\", expected byte data"))`, but got `{:?}`"#,
                     x
                 ),
             }
@@ -352,11 +362,11 @@ mod trivial {
         #[test]
         fn bytes() {
             match from_str::<Trivial<Bytes>>("<root>escaped&#x20;byte_buf</root>") {
-                Err(DeError::Unsupported(msg)) => {
-                    assert_eq!(msg, "binary data content is not supported by XML format")
+                Err(DeError::Custom(msg)) => {
+                    assert_eq!(msg, "invalid type: string \"escaped byte_buf\", expected borrowed bytes")
                 }
                 x => panic!(
-                    r#"Expected `Err(DeError::Unsupported("binary data content is not supported by XML format"))`, but got `{:?}`"#,
+                    r#"Expected `Err(Custom("invalid type: string \"escaped byte_buf\", expected borrowed bytes"))`, but got `{:?}`"#,
                     x
                 ),
             }
@@ -401,11 +411,11 @@ mod trivial {
         #[test]
         fn byte_buf() {
             match from_str::<Trivial<ByteBuf>>("<root><![CDATA[escaped&#x20;byte_buf]]></root>") {
-                Err(DeError::Unsupported(msg)) => {
-                    assert_eq!(msg, "binary data content is not supported by XML format")
+                Err(DeError::Custom(msg)) => {
+                    assert_eq!(msg, "invalid type: string \"escaped&#x20;byte_buf\", expected byte data")
                 }
                 x => panic!(
-                    r#"Expected `Err(DeError::Unsupported("binary data content is not supported by XML format"))`, but got `{:?}`"#,
+                    r#"Expected `Err(Custom("invalid type: string \"escaped&#x20;byte_buf\", expected byte data"))`, but got `{:?}`"#,
                     x
                 ),
             }
@@ -415,11 +425,11 @@ mod trivial {
         #[test]
         fn bytes() {
             match from_str::<Trivial<Bytes>>("<root><![CDATA[escaped&#x20;byte_buf]]></root>") {
-                Err(DeError::Unsupported(msg)) => {
-                    assert_eq!(msg, "binary data content is not supported by XML format")
+                Err(DeError::Custom(msg)) => {
+                    assert_eq!(msg, "invalid type: string \"escaped&#x20;byte_buf\", expected borrowed bytes")
                 }
                 x => panic!(
-                    r#"Expected `Err(DeError::Unsupported("binary data content is not supported by XML format"))`, but got `{:?}`"#,
+                    r#"Expected `Err(Custom("invalid type: string \"escaped&#x20;byte_buf\", expected borrowed bytes"))`, but got `{:?}`"#,
                     x
                 ),
             }
@@ -537,15 +547,18 @@ mod tuple_struct {
 // seq tests are so big, so it in the separate file serde-de-seq.rs to speed-up compilation
 
 macro_rules! maplike_errors {
-    ($type:ty) => {
-        maplike_errors!($type, $type);
+    ($type:ty, $list:ty) => {
+        maplike_errors!($type, $type, $list);
     };
     (
         $attributes:ty,
-        $mixed:ty
+        $mixed:ty,
+        $list:ty
     ) => {
         mod non_closed {
             use super::*;
+            use pretty_assertions::assert_eq;
+            use quick_xml::errors::{Error, IllFormedError};
 
             /// For struct we expect that error about not closed tag appears
             /// earlier than error about missing fields
@@ -554,8 +567,13 @@ macro_rules! maplike_errors {
                 let data = from_str::<$mixed>(r#"<root>"#);
 
                 match data {
-                    Err(DeError::UnexpectedEof) => (),
-                    _ => panic!("Expected `UnexpectedEof`, found {:?}", data),
+                    Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
+                        assert_eq!(cause, IllFormedError::MissedEnd("root".into()))
+                    }
+                    x => panic!(
+                        "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
+                        x
+                    ),
                 }
             }
 
@@ -564,8 +582,13 @@ macro_rules! maplike_errors {
                 let data = from_str::<$attributes>(r#"<root float="42" string="answer">"#);
 
                 match data {
-                    Err(DeError::UnexpectedEof) => (),
-                    _ => panic!("Expected `UnexpectedEof`, found {:?}", data),
+                    Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
+                        assert_eq!(cause, IllFormedError::MissedEnd("root".into()))
+                    }
+                    x => panic!(
+                        "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
+                        x
+                    ),
                 }
             }
 
@@ -574,25 +597,63 @@ macro_rules! maplike_errors {
                 let data = from_str::<$mixed>(r#"<root float="42"><string>answer</string>"#);
 
                 match data {
-                    Err(DeError::UnexpectedEof) => (),
-                    _ => panic!("Expected `UnexpectedEof`, found {:?}", data),
+                    Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
+                        assert_eq!(cause, IllFormedError::MissedEnd("root".into()))
+                    }
+                    x => panic!(
+                        "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
+                        x
+                    ),
+                }
+
+                // Reaches `DeEvent::Eof` in `MapValueSeqAccess::next_element_seed`
+                let data = from_str::<$list>(r#"<root><item>1</item><item>2</item>"#);
+
+                match data {
+                    Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
+                        assert_eq!(cause, IllFormedError::MissedEnd("root".into()))
+                    }
+                    x => panic!(
+                        "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
+                        x
+                    ),
                 }
             }
 
             #[test]
             fn elements_child() {
+                // Reaches `Deserializer::read_text` when text is not present
+                let data = from_str::<$mixed>(r#"<root float="42"><string>"#);
+
+                match data {
+                    Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
+                        assert_eq!(cause, IllFormedError::MissedEnd("string".into()))
+                    }
+                    x => panic!(
+                        "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
+                        x
+                    ),
+                }
+
+                // Reaches `Deserializer::read_text` when text is present
                 let data = from_str::<$mixed>(r#"<root float="42"><string>answer"#);
 
                 match data {
-                    Err(DeError::UnexpectedEof) => (),
-                    _ => panic!("Expected `UnexpectedEof`, found {:?}", data),
+                    Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
+                        assert_eq!(cause, IllFormedError::MissedEnd("string".into()))
+                    }
+                    x => panic!(
+                        "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
+                        x
+                    ),
                 }
             }
         }
 
         mod mismatched_end {
             use super::*;
-            use quick_xml::Error::EndEventMismatch;
+            use pretty_assertions::assert_eq;
+            use quick_xml::errors::{Error, IllFormedError};
 
             /// For struct we expect that error about mismatched tag appears
             /// earlier than error about missing fields
@@ -601,8 +662,17 @@ macro_rules! maplike_errors {
                 let data = from_str::<$mixed>(r#"<root></mismatched>"#);
 
                 match data {
-                    Err(DeError::InvalidXml(EndEventMismatch { .. })) => (),
-                    _ => panic!("Expected `InvalidXml(EndEventMismatch)`, found {:?}", data),
+                    Err(DeError::InvalidXml(Error::IllFormed(cause))) => assert_eq!(
+                        cause,
+                        IllFormedError::MismatchedEnd {
+                            expected: "root".into(),
+                            found: "mismatched".into(),
+                        }
+                    ),
+                    x => panic!(
+                        "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
+                        x
+                    ),
                 }
             }
 
@@ -614,8 +684,17 @@ macro_rules! maplike_errors {
                 );
 
                 match data {
-                    Err(DeError::InvalidXml(EndEventMismatch { .. })) => (),
-                    _ => panic!("Expected `InvalidXml(EndEventMismatch)`, found {:?}", data),
+                    Err(DeError::InvalidXml(Error::IllFormed(cause))) => assert_eq!(
+                        cause,
+                        IllFormedError::MismatchedEnd {
+                            expected: "root".into(),
+                            found: "mismatched".into(),
+                        }
+                    ),
+                    x => panic!(
+                        "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
+                        x
+                    ),
                 }
             }
 
@@ -627,8 +706,17 @@ macro_rules! maplike_errors {
                 );
 
                 match data {
-                    Err(DeError::InvalidXml(EndEventMismatch { .. })) => (),
-                    _ => panic!("Expected `InvalidXml(EndEventMismatch)`, found {:?}", data),
+                    Err(DeError::InvalidXml(Error::IllFormed(cause))) => assert_eq!(
+                        cause,
+                        IllFormedError::MismatchedEnd {
+                            expected: "root".into(),
+                            found: "mismatched".into(),
+                        }
+                    ),
+                    x => panic!(
+                        "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
+                        x
+                    ),
                 }
             }
 
@@ -640,8 +728,17 @@ macro_rules! maplike_errors {
                 );
 
                 match data {
-                    Err(DeError::InvalidXml(EndEventMismatch { .. })) => (),
-                    _ => panic!("Expected `InvalidXml(EndEventMismatch)`, found {:?}", data),
+                    Err(DeError::InvalidXml(Error::IllFormed(cause))) => assert_eq!(
+                        cause,
+                        IllFormedError::MismatchedEnd {
+                            expected: "string".into(),
+                            found: "mismatched".into(),
+                        }
+                    ),
+                    x => panic!(
+                        "Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
+                        x
+                    ),
                 }
             }
         }
@@ -697,7 +794,7 @@ mod map {
         );
     }
 
-    maplike_errors!(HashMap<(), ()>);
+    maplike_errors!(HashMap<(), ()>, HashMap<(), Vec<u32>>);
 }
 
 mod struct_ {
@@ -728,6 +825,12 @@ mod struct_ {
         string: String,
     }
 
+    /// Type where one field represented by list type
+    #[derive(Debug, Deserialize, PartialEq)]
+    struct List {
+        item: Vec<f64>,
+    }
+
     #[test]
     fn elements() {
         let data: Elements = from_str(
@@ -862,8 +965,14 @@ mod struct_ {
             match from_str::<Elements>(
                 "\nexcess text\t<root><float>42</float><string>answer</string></root>",
             ) {
-                Err(DeError::ExpectedStart) => (),
-                x => panic!("Expected Err(ExpectedStart), but got {:?}", x),
+                Err(DeError::Custom(reason)) => assert_eq!(
+                    reason,
+                    "invalid type: string \"excess text\", expected struct Elements",
+                ),
+                x => panic!(
+                    r#"Expected `Err(Custom("invalid type: string \"excess text\", expected struct Elements"))`, but got `{:?}`"#,
+                    x
+                ),
             };
         }
 
@@ -873,8 +982,14 @@ mod struct_ {
             match from_str::<Elements>(
                 "<![CDATA[excess cdata]]><root><float>42</float><string>answer</string></root>",
             ) {
-                Err(DeError::ExpectedStart) => (),
-                x => panic!("Expected Err(ExpectedStart), but got {:?}", x),
+                Err(DeError::Custom(reason)) => assert_eq!(
+                    reason,
+                    "invalid type: string \"excess cdata\", expected struct Elements",
+                ),
+                x => panic!(
+                    r#"Expected `Err(Custom("invalid type: string \"excess cdata\", expected struct Elements"))`, but got `{:?}`"#,
+                    x
+                ),
             };
         }
 
@@ -913,7 +1028,7 @@ mod struct_ {
         }
     }
 
-    maplike_errors!(Attributes, Mixed);
+    maplike_errors!(Attributes, Mixed, List);
 }
 
 mod nested_struct {
@@ -1069,7 +1184,7 @@ mod xml_schema_lists {
                 match err {
                     DeError::$kind(e) => assert_eq!(e, $err),
                     _ => panic!(
-                        "Expected `{}({})`, found `{:?}`",
+                        "Expected `Err({}({}))`, but got `{:?}`",
                         stringify!($kind),
                         $err,
                         err
@@ -1118,7 +1233,7 @@ mod xml_schema_lists {
             "third 3".to_string(),
         ]);
         err!(byte_buf: ByteBuf = r#"<root list="first second  third&#x20;3"/>"#
-                => Unsupported("byte arrays are not supported as `xs:list` items"));
+            => Custom("invalid type: string \"first\", expected byte data"));
 
         list!(unit: () = r#"<root list="1 second  false"/>"# => vec![(), (), ()]);
     }
@@ -1169,7 +1284,7 @@ mod xml_schema_lists {
                 "3".to_string(),
             ]);
             err!(byte_buf: ByteBuf = "<root>first second  third&#x20;3</root>"
-                => Unsupported("byte arrays are not supported as `xs:list` items"));
+                => Custom("invalid type: string \"first\", expected byte data"));
 
             list!(unit: () = "<root>1 second  false</root>" => vec![(), (), ()]);
         }
@@ -1208,7 +1323,7 @@ mod xml_schema_lists {
                 "third&#x20;3".to_string(),
             ]);
             err!(byte_buf: ByteBuf = "<root>first second  third&#x20;3</root>"
-                => Unsupported("byte arrays are not supported as `xs:list` items"));
+                => Custom("invalid type: string \"first\", expected byte data"));
 
             list!(unit: () = "<root>1 second  false</root>" => vec![(), (), ()]);
         }
@@ -1315,15 +1430,13 @@ mod borrow {
 
         #[test]
         fn top_level() {
-            match from_str::<&str>(
-                r#"<root>with escape sequence: &lt;</root>"#,
-            ) {
+            match from_str::<&str>(r#"<root>with escape sequence: &lt;</root>"#) {
                 Err(DeError::Custom(reason)) => assert_eq!(
                     reason,
                     "invalid type: string \"with escape sequence: <\", expected a borrowed string"
                 ),
                 e => panic!(
-                    "Expected `Err(Custom(invalid type: string \"with escape sequence: <\", expected a borrowed string))`, but found {:?}",
+                    r#"Expected `Err(Custom("invalid type: string \"with escape sequence: <\", expected a borrowed string"))`, but got `{:?}`"#,
                     e
                 ),
             }
@@ -1342,7 +1455,7 @@ mod borrow {
                     "invalid type: string \"with escape sequence: <\", expected a borrowed string"
                 ),
                 e => panic!(
-                    "Expected `Err(Custom(invalid type: string \"with escape sequence: <\", expected a borrowed string))`, but found {:?}",
+                    r#"Expected `Err(Custom("invalid type: string \"with escape sequence: <\", expected a borrowed string"))`, but got `{:?}`"#,
                     e
                 ),
             }
@@ -1356,7 +1469,7 @@ mod borrow {
                     "invalid type: string \"with \\\"escape\\\" sequences\", expected a borrowed string"
                 ),
                 e => panic!(
-                    "Expected `Err(Custom(invalid type: string \"with \"escape\" sequences\", expected a borrowed string))`, but found {:?}",
+                    r#"Expected `Err(Custom("invalid type: string \"with \"escape\" sequences\", expected a borrowed string"))`, but got `{:?}`"#,
                     e
                 ),
             }
diff --git a/tests/serde-se.rs b/tests/serde-se.rs
index 4b7fd43..4c5d306 100644
--- a/tests/serde-se.rs
+++ b/tests/serde-se.rs
@@ -255,7 +255,7 @@ mod without_root {
                 match $data.serialize(ser) {
                     Err(DeError::$kind(e)) => assert_eq!(e, $reason),
                     e => panic!(
-                        "Expected `{}({})`, found `{:?}`",
+                        "Expected `Err({}({}))`, but got `{:?}`",
                         stringify!($kind),
                         $reason,
                         e
@@ -1301,7 +1301,7 @@ mod without_root {
                     match $data.serialize(ser) {
                         Err(DeError::$kind(e)) => assert_eq!(e, $reason),
                         e => panic!(
-                            "Expected `{}({})`, found `{:?}`",
+                            "Expected `Err({}({}))`, but got `{:?}`",
                             stringify!($kind),
                             $reason,
                             e
@@ -1768,7 +1768,7 @@ mod with_root {
                 match $data.serialize(ser) {
                     Err(DeError::$kind(e)) => assert_eq!(e, $reason),
                     e => panic!(
-                        "Expected `{}({})`, found `{:?}`",
+                        "Expected `Err({}({}))`, but got `{:?}`",
                         stringify!($kind),
                         $reason,
                         e
diff --git a/tests/unit_tests.rs b/tests/unit_tests.rs
index a5e8c2d..01552a1 100644
--- a/tests/unit_tests.rs
+++ b/tests/unit_tests.rs
@@ -404,9 +404,9 @@ fn test_offset_err_end_element() {
     r.trim_text(true);
 
     match r.read_event() {
-        Err(_) if r.buffer_position() == 2 => (), // error at char 2: no opening tag
+        Err(_) if r.buffer_position() == 0 => (), // error at char 0: no opening tag
         Err(e) => panic!(
-            "expecting buf_pos = 2, found {}, err: {:?}",
+            "expecting buf_pos = 0, found {}, err: {:?}",
             r.buffer_position(),
             e
         ),
diff --git a/tests/xmlrs_reader_tests.rs b/tests/xmlrs_reader_tests.rs
index 16c32ee..5fc0858 100644
--- a/tests/xmlrs_reader_tests.rs
+++ b/tests/xmlrs_reader_tests.rs
@@ -182,7 +182,7 @@ fn sample_ns_short() {
 fn eof_1() {
     test(
         r#"<?xml"#,
-        r#"Error: Unexpected EOF during reading XmlDecl"#,
+        r#"Error: syntax error: processing instruction or xml declaration not closed: `?>` not found before end of input"#,
         true,
     );
 }
@@ -191,7 +191,7 @@ fn eof_1() {
 fn bad_1() {
     test(
         r#"<?xml&.,"#,
-        r#"1:6 Error: Unexpected EOF during reading XmlDecl"#,
+        r#"1:6 Error: syntax error: processing instruction or xml declaration not closed: `?>` not found before end of input"#,
         true,
     );
 }
@@ -201,7 +201,7 @@ fn dashes_in_comments() {
     test(
         r#"<!-- comment -- --><hello/>"#,
         r#"
-        |Error: Unexpected token '--'
+        |Error: ill-formed document: forbidden string `--` was found in a comment
         "#,
         true,
     );
@@ -209,7 +209,7 @@ fn dashes_in_comments() {
     test(
         r#"<!-- comment ---><hello/>"#,
         r#"
-        |Error: Unexpected token '--'
+        |Error: ill-formed document: forbidden string `--` was found in a comment
         "#,
         true,
     );