diff --git a/src/Data/XML/Pickle.hs b/src/Data/XML/Pickle.hs
--- a/src/Data/XML/Pickle.hs
+++ b/src/Data/XML/Pickle.hs
@@ -114,6 +114,7 @@
   , xpElemNodes
   , xpElemBlank
   , xpElemExists
+  , xpElems
    -- ** Character Content
   , xpContent
    -- * Pickler combinators
@@ -144,6 +145,7 @@
   -- without any special treatment and unpickle as stated.
   , xpFindMatches
   , xpAll
+  , xpSubsetAll
   , xpList0
   , xpSeqWhile
   , xpList
@@ -164,7 +166,7 @@
   , xpWrapMaybe
   , xpWrapMaybe_
   , xpAssert
-  , xpElems
+  , xpUnliftElems
   -- *** Book keeping
   -- | Change the semantics of picklers
   , xpIsolate
@@ -192,7 +194,7 @@
 import qualified Control.Category as Cat
 
 import Data.Either
-import Data.List(intersperse)
+import Data.List(partition)
 import Data.Monoid(Monoid, mempty)
 
 import Control.Exception
@@ -204,15 +206,65 @@
 
 import Data.XML.Types
 
+data UnpickleError = ErrorMessage Text
+                   | TraceStep (Text, Text) UnpickleError
+                   | Variants [UnpickleError]
+                   deriving Typeable
+
+upe :: String -> UnpickleError
+upe e = ErrorMessage (Text.pack e)
+
+replace :: [(Text,Text)] -> [(Text,Text)] -> [(Text,Text)]
+replace ns ss = go ns ss
+  where
+    go []     ss     = ss
+    go (n:ns) (s:ss) = n : (go ns ss)
+    go  ns s = error $ "Empty list while trying to replace " ++
+                           show ss ++ " with " ++ show ns
+
+swapStack ns (TraceStep s e) = TraceStep ns e
+swapStack ns e = error $ "Can't replace non-trace step" ++ show e
+
+showTr (name, "") = Text.unpack name
+showTr (name, extra) = concat [Text.unpack name , " (", Text.unpack extra, ")"]
+
+printUPE (ErrorMessage m) = [Text.unpack m]
+printUPE (TraceStep t es) = ("-> " ++ showTr  t) : printUPE es
+printUPE (Variants vs) = concat
+                       . zipWith (:) (map (\x -> show x ++ ")") [1..])
+                       . (map $ map ( "  " ++))
+                       $ (printUPE <$> vs)
+
+instance Show UnpickleError where
+   show e = "Error while unpickling:\n" ++ (unlines $ map ("  " ++) (printUPE e))
+
+instance Exception UnpickleError
+
 data PU t a = PU
   { unpickleTree :: t
-                    -> Either String (a, (Maybe t, Bool))
+                    -> Either UnpickleError (a, (Maybe t, Bool))
                     -- ^ Either an error or the return value,
                     -- any remaining input and a Bool value indicating whether
                     -- all nested picklers where clean
   , pickleTree :: a -> t
   }
 
+mapError f xp = PU { unpickleTree = mapLeft f . unpickleTree xp
+                   , pickleTree = pickleTree xp
+                   }
+
+
+infixl 6 <++>
+(<++>) :: (Text, Text) -> UnpickleError -> UnpickleError
+(<++>) s e = TraceStep s e
+
+
+infixr 0 <?>
+(<?>) tr = mapError (swapStack tr)
+
+infixr 1 <?+>
+(<?+>) tr = mapError ((<++>) tr)
+
 data UnresolvedEntityException = UnresolvedEntityException
                                    deriving (Typeable, Show)
 instance Exception UnresolvedEntityException
@@ -232,7 +284,7 @@
 pickle = pickleTree
 
 -- | unpickle a tree, throws away information concerning cleannes
-unpickle :: PU t a -> t -> Either String a
+unpickle :: PU t a -> t -> Either UnpickleError a
 unpickle xp x = fst <$> unpickleTree xp x
 
 
@@ -256,7 +308,7 @@
 -- | return one element, untouched
 xpHead :: PU [a] a
 xpHead = PU {unpickleTree = \t -> case t of
-                [] -> Left $ "xpHead: No element remaining"
+                [] -> Left $ ("xpHead","") <++> upe "No element remaining"
                 t:ts -> Right (t , (if null ts then Nothing else Just ts, True))
             , pickleTree = return
             }
@@ -269,36 +321,39 @@
 xpText0 :: PU Text Text
 xpText0 = xpId
 
-
 -- | Test predicate when unpickling. Fails with given error message when the
 -- predicate return false.
 --
 -- N.B.: The predicate will only be tested while /unpickling/. When pickling,
 -- this is a noop.
-xpAssert :: String -> (a -> Bool) -> PU t a -> PU t a
-xpAssert error p xp = PU { unpickleTree = \t -> case unpickleTree xp t of
-                                   Left e -> Left e
+xpAssert :: Text -> (a -> Bool) -> PU t a -> PU t a
+xpAssert err p xp = PU { unpickleTree = \t -> case unpickleTree xp t of
+                                   Left e -> Left $ ("xpAssert",err) <++> e
                                    Right (r,c) -> case p r of
                                        True -> Right (r,c)
-                                       False -> Left error
-                         , pickleTree = pickleTree xp
-                         }
+                                       False -> Left $ assertErr
 
+                       , pickleTree = pickleTree xp
+                       }
+  where
+    assertErr = ("xpAssert",err) <++> upe "Assertion failed"
+
+
 -- | Like 'xpText0', but fails on non-empty input.
 xpText :: PU Text Text
-xpText = xpAssert "xpText: Text value is null" Text.null xpText0
+xpText = ("xpText","") <?> xpAssert "Input is empty" Text.null xpText0
 
 -- | Adapts a list of nodes to a single node. Generally used at the top level of
 -- an XML document.
 xpRoot ::PU [a] b -> PU a b
 xpRoot pa = PU
        { unpickleTree = \t -> case unpickleTree pa [t] of
-            Left l -> Left l
+            Left l -> Left $ ("xpRoot","") <++> l
             Right (a,(Nothing,True)) -> Right (a, (Nothing,True ))
             Right (a,(_      ,_   )) -> Right (a, (Nothing,False))
        , pickleTree = \t -> case pickleTree pa t of
            [t1] -> t1
-           _    -> error "pickler called by xpRoot must output only one element"
+           _    -> error "pickler called by xpRoot must output exactly one element"
        }
 
 
@@ -316,13 +371,14 @@
         , pickleTree = \value -> [(name, [ContentText $ pickleTree pu value])]
         }
   where
+    tr = ("xpAttr" , Text.pack $ ppName name)
     doUnpickle attrs = case getFirst ((== name) . fst) attrs of
-      Nothing -> Left $ "attribute " ++ ppName name ++ " not found."
+      Nothing -> Left $ tr <++> upe ("attribute not found")
       Just ((_,[ContentText x]), rem) -> case unpickleTree pu x of
-        Left e -> Left $ "in attribute " ++ ppName name ++ " : " ++ e
+        Left e -> Left $ tr <++> e
         Right (y,(_,c)) -> let rem' = if null rem then Nothing else Just rem
                          in Right (y,(rem',c))
-      _ -> Left $ "xpAttr: Unresolved entities in " ++ ppName name ++ "."
+      _ -> Left $ tr <++> upe ("Unresolved entities in " ++ ppName name ++ ".")
 
 -- | Pickle attribute if Just is given, on unpickling return Just <val> when
 -- the attribute is found, Nothing otherwise
@@ -378,18 +434,61 @@
     doUnpickleTree nodes = case getFirst (nodeElementNameHelper name) nodes of
       Just ((NodeElement (Element _ attrs children)), rem) ->
         case unpickleTree attrP attrs of
-          Left e -> Left $ "in element " ++ ppName name ++ " : " ++ e
+          Left e -> Left $ tr <++> e
           Right (x,(_,ca)) -> case unpickleTree nodeP
                                     $ flattenContent children of
-            Left e -> Left $ "in element " ++ ppName name ++ " : " ++ e
+            Left e -> Left $ tr <++> e
             Right (y,(_,cc)) ->
               let rem' = if null rem then Nothing else Just rem
               in Right ((x,y), (rem' , ca && cc))
-      _ -> Left $ "xpElem: " ++ ppName name ++ " not found."
+      _ -> Left $ tr  <++> upe "Element not found"
 
+    tr = ("xpElem", Text.pack $ ppName name)
+
     nodeElementNameHelper name (NodeElement (Element n _ _)) = n == name
     nodeElementNameHelper _ _ = False
 
+-- | Handle all elements with a given name. The unpickler will fail when any of
+-- the elements fails to unpickle.
+xpElems :: Name -- ^ Name of the elements
+        -> PU [Attribute] a -- ^ pickler for attributes
+        -> PU [Node] n -- ^ pickler for child nodes
+        -> PU [Node] [(a, n)]
+xpElems name attrs children = PU { unpickleTree = \t ->
+                     let (targets, rest) = partition isThisElem t
+                         rest' = if null rest then Nothing else Just rest
+                     in
+                     case unpickleTree (xpAll $ xpElem name attrs children) targets of
+                         Left e -> Left $ tr <++> e
+                         Right (r, (_, c)) -> Right (r,(rest', c && not (null rest)))
+                     , pickleTree = pickleTree (xpAll $ xpElem name attrs children)
+
+             }
+  where
+    isThisElem (NodeElement (Element name _ _)) = True
+    isThisElem _ = False
+
+    tr = ("xpElems", Text.pack $ ppName name)
+
+-- | For unpickling, apply the given pickler to a subset of the elements
+-- determined by a given predicate
+--
+-- Pickles like 'xpAll'
+xpSubsetAll :: (a -> Bool) -- ^ predicate to select the subset
+            -> PU [a] b    -- ^ pickler to apply on the subset
+            -> PU [a] [b]
+xpSubsetAll pred xp = PU { unpickleTree = \t ->
+                     let (targets, rest) = partition pred t
+                         rest' = if null rest then Nothing else Just rest
+                     in
+                     case unpickleTree (xpAll xp) targets of
+                         Left e -> Left $ ("xpSubsetAll","") <++> e
+                         Right (r, (_, c)) ->
+                             Right (r,(rest', c && not (null rest)))
+                     , pickleTree = pickleTree (xpAll $ xp)
+
+             }
+
 -- | pickle Element without restriction on the name.
 -- the name as taken / returned as the first element of the triple
 xpElemWithName :: PU [Attribute] a  -- ^ pickler for attributes
@@ -405,15 +504,17 @@
     doUnpickleTree nodes = case getFirst nodeElementHelper nodes of
       Just ((NodeElement (Element name attrs children)), rem) ->
         case unpickleTree attrP attrs of
-          Left e -> Left $ "in element " ++ ppName name ++ " : " ++ e
+          Left e -> Left $ tr <++> e
           Right (x,(_,ca)) -> case unpickleTree nodeP $
                                      flattenContent children of
-            Left e -> Left $ "in element " ++ ppName name ++ " : " ++ e
+            Left e -> Left $ tr <++> e
             Right (y,(_,cc)) ->
               let rem' = if null rem then Nothing else Just rem
               in Right ((name,x,y), (rem' , ca && cc))
-      _ -> Left $ "xpElemWithName: no element found."
+      _ -> Left $ tr <++> upe "No element found"
 
+    tr = ("xpElemWithName", "")
+
     nodeElementHelper (NodeElement (Element _ _ _)) = True
     nodeElementHelper _ = False
 
@@ -440,10 +541,13 @@
           return ((name', attrs', nodes')
                  ,(if null rem then Nothing else Just rem,   cn && ca && cns))
         ) of
-          Left e -> Left $ "in xpElemByNamespace with element " ++ ppName name ++ " : " ++ e
+          Left e -> Left $ (tr $ ppName name)  <++> e
           Right r -> Right r
-      _ -> Left $ "xpElemByNamespace: no element found."
+      _ -> Left $ (tr "") <++> upe "No element found"
 
+    tr a = ("xpElemByNamespace", if null a then ns
+                                 else Text.concat [ns, " ; ", Text.pack a])
+
     nodeElementNSHelper ns (NodeElement (Element n _ _)) = nameNamespace n == Just ns
     nodeElementNSHelper ns _ = False
 
@@ -457,7 +561,7 @@
       Just ((NodeElement e@(Element _ _ _)), rem) ->
         let rem' = if null rem then Nothing else Just rem
         in Right (e, (rem', True))
-      _ -> Left $ "xpElemVerbatim: no element found."
+      _ -> Left $ ("xpElemVerbatim","") <++> upe "no element found."
 
     nodeElementHelper (NodeElement (Element _ _ _)) = True
     nodeElementHelper _ = False
@@ -487,31 +591,31 @@
 
 -- | Get the Content from a node
 xpContent :: PU Text a -> PU [Node] a
-xpContent xp = PU
+xpContent xp = ("xpContent","") <?+> PU
        { unpickleTree = doUnpickle
        , pickleTree = return . NodeContent . ContentText . pickleTree xp
        } where
      doUnpickle nodes = case getFirst nodeContentHelper nodes of
        Just ((NodeContent (ContentText t)), rem) -> case unpickleTree xp t of
          Right (a,(_,c)) -> Right (a, (if null rem then Nothing else Just rem,c))
-         Left l -> Left $ "In xpContent: " ++ l
+         Left l -> Left l
        Just ((NodeContent (ContentEntity t)), _) ->
-           Left $ "xpContent: unresolved entity" ++ show t ++ "."
-       _ -> Left $ "xpContent: No content found"
+            Left . upe $ "Unresolved entity" ++ show t ++ "."
+       _ -> Left $ upe "No content found"
 
      nodeContentHelper (NodeContent _) = True
      nodeContentHelper _ = False
 
--- | Unlift a pickler on Nodes to a Pickler on Elements. Generated
--- Nodes that are not Elements will be silently discarded
-xpElems :: PU [Node] a -> PU [Element] a
-xpElems xp = PU
+-- | Unlift a pickler on Nodes to a Pickler on Elements. Nodes generated during
+-- pickling that are not Elements will be silently discarded
+xpUnliftElems :: PU [Node] a -> PU [Element] a
+xpUnliftElems xp = PU
              { unpickleTree = doUnpickle
              , pickleTree = nodesToElems . pickleTree xp
              }
   where
     doUnpickle nodes = case unpickleTree xp (map NodeElement nodes) of
-        Left e -> Left $ "In xpElems :" ++ e
+        Left e -> Left $ ("xpUnliftElems","") <++> e
         Right (a,(r,c)) -> let r' = case r of
                                       Nothing -> Nothing
                                       Just rs' -> case nodesToElems rs' of
@@ -585,11 +689,12 @@
 -- | Combines 2 picklers
 
 xp2Tuple :: PU [a] b1 -> PU [a] b2 -> PU [a] (b1, b2)
-xp2Tuple xp1 xp2 = PU {pickleTree = \(t1, t2) ->
+xp2Tuple xp1 xp2 = ("xp2Tuple","") <?+>
+                   PU {pickleTree = \(t1, t2) ->
                         pickleTree xp1 t1 ++ pickleTree xp2 t2
                     , unpickleTree = doUnpickleTree
                     } where
-  doUnpickleTree r0 = mapLeft ("In xp2Tuple: " ++) $ do
+  doUnpickleTree r0 = do
     -- The /Either String/ monad
     (x1 ,(r1,c1)) <- getRest <$> unpickleTree xp1 r0
     (x2 ,(r ,c2)) <-             unpickleTree xp2 r1
@@ -597,21 +702,22 @@
 
 -- | 'xp2Tuple' (/compat/)
 xpPair :: PU [a] b1 -> PU [a] b2 -> PU [a] (b1, b2)
-xpPair = xp2Tuple
+xpPair l r = ("xpPair", "") <?> xp2Tuple l r
 
 -- | 'xp2Tuple'
-(<++>) :: PU [a] b1 -> PU [a] b2 -> PU [a] (b1, b2)
-(<++>) = xp2Tuple
+(<#>) :: PU [a] b1 -> PU [a] b2 -> PU [a] (b1, b2)
+(<#>) l r = ("(<#>)","") <?> xp2Tuple l r
 
 -- | Combines 3 picklers
 xp3Tuple  :: PU [a] a1 -> PU [a] a2 -> PU [a] a3 -> PU [a] (a1, a2, a3)
-xp3Tuple xp1 xp2 xp3 = PU {pickleTree = \(t1, t2, t3) ->
+xp3Tuple xp1 xp2 xp3 = ("xp3Tuple","") <?+>
+                     PU {pickleTree = \(t1, t2, t3) ->
                         pickleTree xp1 t1
                         ++ pickleTree xp2 t2
                         ++ pickleTree xp3 t3
                     , unpickleTree = doUnpickleTree
                     } where
-  doUnpickleTree r0 = mapLeft ("In xp3Tuple: " ++) $ do
+  doUnpickleTree r0 = do
     (x1 ,(r1,c1)) <- getRest <$> unpickleTree xp1 r0
     (x2 ,(r2,c2)) <- getRest <$> unpickleTree xp2 r1
     (x3 ,(r ,c3)) <-             unpickleTree xp3 r2
@@ -619,20 +725,21 @@
 
 -- | 'xp3Tuple' (/compat/)
 xpTriple  :: PU [a] a1 -> PU [a] a2 -> PU [a] a3 -> PU [a] (a1, a2, a3)
-xpTriple = xp3Tuple
+xpTriple l m r = ("xpTriple","") <?> xp3Tuple l m r
 
 -- | Combines 4 picklers
 xp4Tuple  :: PU [a] a1 -> PU [a] a2 -> PU [a] a3 -> PU [a] a4
              -> PU [a] (a1, a2, a3,a4)
 xp4Tuple xp1 xp2 xp3 xp4
-     = PU {pickleTree = \(t1, t2, t3, t4) ->
+     = ("xp4Tuple","") <?+>
+       PU {pickleTree = \(t1, t2, t3, t4) ->
                         pickleTree xp1 t1
                         ++ pickleTree xp2 t2
                         ++ pickleTree xp3 t3
                         ++ pickleTree xp4 t4
                     , unpickleTree = doUnpickleTree
                     } where
-  doUnpickleTree r0 = mapLeft ("In xp4Tuple: " ++) $ do
+  doUnpickleTree r0 =  do
     (x1 ,(r1, c1)) <- getRest <$> unpickleTree xp1 r0
     (x2 ,(r2, c2)) <- getRest <$> unpickleTree xp2 r1
     (x3 ,(r3, c3)) <- getRest <$> unpickleTree xp3 r2
@@ -643,7 +750,8 @@
 xp5Tuple  :: PU [a] a1 -> PU [a] a2 -> PU [a] a3 -> PU [a] a4 -> PU [a] a5
              -> PU [a] (a1, a2, a3, a4, a5)
 xp5Tuple xp1 xp2 xp3 xp4 xp5
-  = PU {pickleTree = \(t1, t2, t3, t4, t5) ->
+  = ("xp5Tuple","") <?+>
+    PU {pickleTree = \(t1, t2, t3, t4, t5) ->
                         pickleTree xp1 t1
                         ++ pickleTree xp2 t2
                         ++ pickleTree xp3 t3
@@ -651,7 +759,7 @@
                         ++ pickleTree xp5 t5
                     , unpickleTree = doUnpickleTree
                     } where
-  doUnpickleTree r0 = mapLeft ("In xp5Tuple: " ++) $ do
+  doUnpickleTree r0 = do
     (x1 ,(r1,c1)) <- getRest <$> unpickleTree xp1 r0
     (x2 ,(r2,c2)) <- getRest <$> unpickleTree xp2 r1
     (x3 ,(r3,c3)) <- getRest <$> unpickleTree xp3 r2
@@ -664,7 +772,8 @@
              -> PU [a] a6
              -> PU [a] (a1, a2, a3, a4, a5, a6)
 xp6Tuple xp1 xp2 xp3 xp4 xp5 xp6
-  = PU {pickleTree = \(t1, t2, t3, t4, t5, t6) ->
+  = ("xp6Tuple","") <?+>
+    PU {pickleTree = \(t1, t2, t3, t4, t5, t6) ->
                         pickleTree xp1 t1
                         ++ pickleTree xp2 t2
                         ++ pickleTree xp3 t3
@@ -673,7 +782,7 @@
                         ++ pickleTree xp6 t6
                     , unpickleTree = doUnpickleTree
                     } where
-  doUnpickleTree r0 = mapLeft ("In xp5Tuple: " ++) $ do
+  doUnpickleTree r0 = do
     (x1 ,(r1,c1)) <- getRest <$> unpickleTree xp1 r0
     (x2 ,(r2,c2)) <- getRest <$> unpickleTree xp2 r1
     (x3 ,(r3,c3)) <- getRest <$> unpickleTree xp3 r2
@@ -695,9 +804,10 @@
 --
 -- When unpickling, only give access to the first element
 xpIsolate :: PU [t] a -> PU [t] a
-xpIsolate xp = PU { pickleTree = pickleTree xp
+xpIsolate xp = ("xpIsolate","") <?+>
+               PU { pickleTree = pickleTree xp
                , unpickleTree = \xs -> case xs of
-                 [] -> Left $ "xpIsolate: no elements left"
+                 [] -> Left $ upe "No elements left"
                  (x:xs) -> case unpickleTree xp [x] of
                    Left l -> Left l
                    Right (v,(r,c)) -> Right (v,(handleRest r xs, c))
@@ -708,7 +818,8 @@
 
 -- | apply a bijection before pickling / after unpickling
 xpWrap :: (a -> b) -> (b -> a) -> PU t a -> PU t b
-xpWrap to from xp = PU { unpickleTree = \x -> (first to) <$> unpickleTree xp x
+xpWrap to from xp = ("xpWrap","") <?+>
+                    PU { unpickleTree = \x -> (first to) <$> unpickleTree xp x
                        , pickleTree = pickleTree xp . from
                        }
 
@@ -716,7 +827,8 @@
 -- Fails on unpickle if 'read' fails.
 xpPrim :: (Show a, Read a) => PU Text a
 xpPrim = PU { unpickleTree = \x -> case reads $ Text.unpack x of
-                 []       -> Left $ "In xpPrim: couldn't read " ++ show x ++ "."
+                 []       -> Left $ ("xpPrim","") <++>
+                               upe ("Couldn't read " ++ show x ++ ".")
                  (r,rest):_  -> Right (r,(Nothing, True))
             ,  pickleTree = Text.pack . show
             }
@@ -734,13 +846,16 @@
             Right (r,(_,c)) -> Right (r, c)
         in Right (fst <$> rs, (if null ls then Nothing else Just ls,all snd rs))
 
+-- TODO: Replace with clean / xpAll?
+
 -- | Tries to apply the pickler to all the remaining elements;
 -- fails if any of them don't match
 xpAll :: PU [a] b -> PU [a] [b]
 xpAll xp = PU { unpickleTree = \x ->
                  let Right (xs, (rs,c)) = unpickleTree (xpFindMatches xp) x
                    in case rs of
-                      Just (_:_) -> Left "In xpAll: not all Elements matched"
+                      Just (_:_) -> Left $ ("xpAll","") <++>
+                                      upe "not all Elements matched"
                       _ -> Right (xs, (Nothing,c))
               , pickleTree = \xs -> pickleTree xp =<< xs
               }
@@ -800,7 +915,8 @@
 
 -- | Like xpWrap, but strips Just (and treats Nothing as a failure) during unpickling.
 xpWrapMaybe :: (a -> Maybe b) -> (b -> a) -> PU t a -> PU t b
-xpWrapMaybe = xpWrapMaybe_ "xpWrapMaybe can't encode Nothing value"
+xpWrapMaybe a2b b2a pua = ("xpWrapMaybe","") <?>
+                 xpWrapMaybe_ "xpWrapMaybe can't encode Nothing" a2b b2a pua
 
 -- | Like xpWrap, but strips Just (and treats Nothing as a failure) during unpickling,
 -- with specified error message for Nothing value.
@@ -810,7 +926,7 @@
             Right (val, rest) ->
                 case a2b val of
                     Just val' -> Right (val', rest)
-                    Nothing   -> Left errorMsg
+                    Nothing   -> Left $ ("xpWrapMaybe_","") <++> upe errorMsg
             Left err  -> Left err,
         pickleTree = \value -> pickleTree pua (b2a value)
     }
@@ -820,10 +936,11 @@
 --
 -- not to be confuesd with 'xpEither'
 xpWrapEither :: (a -> Either String b) -> (b -> a) -> PU t a -> PU t b
-xpWrapEither a2b b2a pua = PU {
+xpWrapEither a2b b2a pua = ("xpWrapEither","") <?+>
+     PU {
         unpickleTree = \t -> case unpickleTree pua t of
-            Right (val, rest) -> (flip (,) rest) <$> a2b val
-            Left err  -> Left $ "xpWrapEither failed: "++err,
+            Right (val, rest) -> mapLeft upe $ (flip (,) rest) <$> a2b val
+            Left err -> Left  err,
         pickleTree = \value -> pickleTree pua (b2a value)
     }
 
@@ -851,7 +968,7 @@
                       Left errs -> Left $ err : errs
                       Right r -> Right r
         in case tryAll picklers of
-          Left errs -> Left $ "In xpAlt:\n  " ++ concat (intersperse ";\n  " errs)
+          Left errs -> Left $ ("xpAlt","") <++> Variants errs
           Right r -> Right r
 
 
@@ -869,9 +986,10 @@
   where
     doUnpickle t = case unpickleTree xpl t of
                     Right (val, rst) -> Right (Left val, rst)
-                    Left err  -> case unpickleTree xpr t of
+                    Left errl  -> case unpickleTree xpr t of
                       Right (val, rst) -> Right (Right val, rst)
-                      Left _ -> Left $ "xpEither: both unpicklers failed"
+                      Left errr -> Left $ ("xpEither","")
+                                          <++> Variants [errl, errr]
 
 -- | Pickler that during pickling always uses the first pickler, and during
 -- unpickling tries the first, and on failure then tries the second.
@@ -881,7 +999,8 @@
              Right (val1, rest) -> Right (val1, rest)
              Left  err1 -> case unpickleTree pu2 t of
                  Right (val2, rest) -> Right (val2, rest)
-                 Left  err2 -> Left $ "Both xpTryCatch picklers failed: <" ++ err1 ++ "> <" ++ err2 ++ ">"
+                 Left  err2 -> Left $ ("xpTryCatch","")
+                                <++> Variants [err1, err2]
     , pickleTree = pickleTree pu1
     }
 
@@ -889,13 +1008,13 @@
 --
 -- Encodes nothing, always fails during unpickling. (Same as @'xpThrow' \"got xpZero\"@).
 xpZero :: PU [t] a
-xpZero = xpThrow "got xpZero"
+xpZero = ("xpZero","") <?> xpThrow "got xpZero"
 
 -- | No output when pickling, always generates an error with the specified message on unpickling.
 xpThrow :: String    -- ^ Error message
         -> PU [t] a
 xpThrow msg = PU
-  { unpickleTree = \t -> Left msg
+  { unpickleTree = \t -> Left $ ("xpThrow",Text.pack msg) <++> upe msg
   , pickleTree = const []
   }
 
@@ -907,7 +1026,7 @@
 xpClean xp = PU { unpickleTree = \x -> case unpickleTree xp x of
                      Left l -> Left l
                      Right (y, (Nothing, c )) -> Right (y, (Nothing, c ))
-                     _ -> Left $ "xpClean: not clean"
+                     _ -> Left $ ("xpClean","") <++> upe "not clean"
 
                 , pickleTree = pickleTree xp
                 }
@@ -920,9 +1039,9 @@
 xpRecursiveClean xp = PU { unpickleTree = \x -> case unpickleTree xp x of
                      Left l -> Left l
                      Right (_, (Just _, _)) ->
-                       Left $ "xpRecursiveClean: not clean"
+                       Left $ ("xpRecursiveClean","") <++> upe "not clean"
                      Right (_, (Nothing, False)) ->
-                       Left $ "xpRecursiveClean: not recursive clean"
+                       Left $ ("xpRecursiveClean","") <++> upe "not recursively clean"
                      Right (y , (Nothing, True)) -> Right (y , (Nothing, True))
                      , pickleTree = pickleTree xp
                 }
diff --git a/xml-picklers.cabal b/xml-picklers.cabal
--- a/xml-picklers.cabal
+++ b/xml-picklers.cabal
@@ -1,10 +1,18 @@
 Cabal-Version: >= 1.2
 Name: xml-picklers
-Version: 0.1
+Version: 0.2
 Synopsis: XML picklers based on xml-types, ported from hexpat-pickle
 Description:
   A library of combinators that allows Haskell data structures to be pickled
   (serialized) to/from a representation of XML as defined in xml-types
+  .
+  Release history
+  .
+  [0.2] Error system overhaul.
+  .
+  New picklers: @xpSubsetAll@, @xpElems@
+  .
+  [0.1] Initial release
 Category: XML
 License: BSD3
 License-File: LICENSE
