diff --git a/config/server.go b/config/server.go
index 3e7e8be81d77c02229bdbfaabe2ce4e38b44cf11..162118956e11af33fb77e4d1240238e2163d33ff 100644
--- a/config/server.go
+++ b/config/server.go
@@ -6,6 +6,7 @@ import (
 	"net"
 	"strings"
 
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -29,7 +30,7 @@ func (g *Global) SetDefaultGlobalConfigValues() error {
 	if g.RouterID == 0 {
 		rtrid, err := generateRouterID()
 		if err != nil {
-			return fmt.Errorf("Unable to determine router ID: %v", err)
+			return errors.Wrap(err, "Unable to determine router ID")
 		}
 		g.RouterID = rtrid
 	}
@@ -64,7 +65,7 @@ func _getHighestIP(ifs []net.Interface) (net.IP, error) {
 	for _, iface := range ifs {
 		addrs, err := iface.Addrs()
 		if err != nil {
-			return nil, fmt.Errorf("Unable to get interface addrs for %s: %v", iface.Name, err)
+			return nil, errors.Wrapf(err, "Unable to get interface addrs for %s", iface.Name)
 		}
 
 		for _, addr := range addrs {
@@ -92,7 +93,7 @@ func _getHighestIP(ifs []net.Interface) (net.IP, error) {
 func getLoopbackIP() (net.IP, error) {
 	iface, err := net.InterfaceByName("lo")
 	if err != nil {
-		return nil, fmt.Errorf("Unable to get interface lo: %v", err)
+		return nil, errors.Wrap(err, "Unable to get interface lo")
 	}
 
 	return _getLoopbackIP(iface)
@@ -101,7 +102,7 @@ func getLoopbackIP() (net.IP, error) {
 func _getLoopbackIP(iface *net.Interface) (net.IP, error) {
 	addrs, err := iface.Addrs()
 	if err != nil {
-		return nil, fmt.Errorf("Unable to get interface addresses: %v", err)
+		return nil, errors.Wrap(err, "Unable to get interface addresses")
 	}
 
 	candidates := make([]net.IP, 0)
diff --git a/net/prefix.go b/net/prefix.go
index d2287bdd42b2d5458b2ffbe304b5c1b08ce99c35..9e121de78a90a04187816ed03f5850621c75835c 100644
--- a/net/prefix.go
+++ b/net/prefix.go
@@ -8,6 +8,7 @@ import (
 	"strings"
 
 	"github.com/bio-routing/bio-rd/net/api"
+	"github.com/pkg/errors"
 )
 
 // Prefix represents an IPv4 prefix
@@ -62,7 +63,7 @@ func StrToAddr(x string) (uint32, error) {
 	for i := 0; i < 4; i++ {
 		y, err := strconv.Atoi(parts[i])
 		if err != nil {
-			return 0, fmt.Errorf("Unable to convert %q to int: %v", parts[i], err)
+			return 0, errors.Wrapf(err, "Unable to convert %q to int", parts[i])
 		}
 
 		if y > 255 {
diff --git a/protocols/bgp/packet/decoder.go b/protocols/bgp/packet/decoder.go
index 5ad26c878dfb728531f2a4bef87a3894c50640ed..f002d31fda13e57506a03003b3f1124632806d27 100644
--- a/protocols/bgp/packet/decoder.go
+++ b/protocols/bgp/packet/decoder.go
@@ -6,6 +6,7 @@ import (
 	"net"
 
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -13,12 +14,12 @@ import (
 func Decode(buf *bytes.Buffer, opt *DecodeOptions) (*BGPMessage, error) {
 	hdr, err := decodeHeader(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Failed to decode header: %v", err)
+		return nil, errors.Wrap(err, "Failed to decode header")
 	}
 
 	body, err := decodeMsgBody(buf, hdr.Type, hdr.Length-MinLen, opt)
 	if err != nil {
-		return nil, fmt.Errorf("Failed to decode message: %v", err)
+		return nil, errors.Wrap(err, "Failed to decode message")
 	}
 
 	return &BGPMessage{
@@ -132,7 +133,7 @@ func invalidErrCode(n *BGPNotification) (*BGPNotification, error) {
 func DecodeOpenMsg(buf *bytes.Buffer) (*BGPOpen, error) {
 	msg, err := _decodeOpenMsg(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode OPEN message: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode OPEN message")
 	}
 	return msg.(*BGPOpen), err
 }
@@ -160,7 +161,7 @@ func _decodeOpenMsg(buf *bytes.Buffer) (interface{}, error) {
 
 	msg.OptParams, err = decodeOptParams(buf, msg.OptParmLen)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode optional parameters: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode optional parameters")
 	}
 
 	return msg, nil
@@ -187,7 +188,7 @@ func decodeOptParams(buf *bytes.Buffer, optParmLen uint8) ([]OptParam, error) {
 		case CapabilitiesParamType:
 			caps, err := decodeCapabilities(buf, o.Length)
 			if err != nil {
-				return nil, fmt.Errorf("Unable to decode capabilities: %v", err)
+				return nil, errors.Wrap(err, "Unable to decode capabilities")
 			}
 
 			o.Value = caps
@@ -210,7 +211,7 @@ func decodeCapabilities(buf *bytes.Buffer, length uint8) (Capabilities, error) {
 	for read < length {
 		cap, err := decodeCapability(buf)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode capability: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode capability")
 		}
 
 		ret = append(ret, cap)
@@ -242,20 +243,20 @@ func decodeCapability(buf *bytes.Buffer) (Capability, error) {
 	case AddPathCapabilityCode:
 		addPathCap, err := decodeAddPathCapability(buf)
 		if err != nil {
-			return cap, fmt.Errorf("Unable to decode add path capability: %v", err)
+			return cap, errors.Wrap(err, "Unable to decode add path capability")
 		}
 		cap.Value = addPathCap
 	case ASN4CapabilityCode:
 		asn4Cap, err := decodeASN4Capability(buf)
 		if err != nil {
-			return cap, fmt.Errorf("Unable to decode 4 octet ASN capability: %v", err)
+			return cap, errors.Wrap(err, "Unable to decode 4 octet ASN capability")
 		}
 		cap.Value = asn4Cap
 	default:
 		for i := uint8(0); i < cap.Length; i++ {
 			_, err := buf.ReadByte()
 			if err != nil {
-				return cap, fmt.Errorf("Read failed: %v", err)
+				return cap, errors.Wrap(err, "Read failed")
 			}
 		}
 	}
diff --git a/protocols/bgp/packet/mp_reach_nlri.go b/protocols/bgp/packet/mp_reach_nlri.go
index b714dc19b03333930e6b9b60d53093e15f957314..350c090935649906a2db66d5d5a692c5d21a22b3 100644
--- a/protocols/bgp/packet/mp_reach_nlri.go
+++ b/protocols/bgp/packet/mp_reach_nlri.go
@@ -6,6 +6,7 @@ import (
 
 	bnet "github.com/bio-routing/bio-rd/net"
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -65,7 +66,7 @@ func deserializeMultiProtocolReachNLRI(b []byte, addPath bool) (MultiProtocolRea
 
 	n.NextHop, err = bnet.IPFromBytes(variable[:nextHopLength])
 	if err != nil {
-		return MultiProtocolReachNLRI{}, fmt.Errorf("Failed to decode next hop IP: %v", err)
+		return MultiProtocolReachNLRI{}, errors.Wrap(err, "Failed to decode next hop IP")
 	}
 	budget -= int(nextHopLength)
 
diff --git a/protocols/bgp/packet/nlri.go b/protocols/bgp/packet/nlri.go
index 1f4f7f6e4293771349b60d1e581e697f5fa085d4..babb026d144ab97ad89d6894f8d23eaecb91c83b 100644
--- a/protocols/bgp/packet/nlri.go
+++ b/protocols/bgp/packet/nlri.go
@@ -7,6 +7,7 @@ import (
 
 	bnet "github.com/bio-routing/bio-rd/net"
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -32,7 +33,7 @@ func decodeNLRIs(buf *bytes.Buffer, length uint16, afi uint16, addPath bool) (*N
 	for p < length {
 		nlri, consumed, err = decodeNLRI(buf, afi, addPath)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode NLRI: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode NLRI")
 		}
 		p += uint16(consumed)
 
@@ -59,7 +60,7 @@ func decodeNLRI(buf *bytes.Buffer, afi uint16, addPath bool) (*NLRI, uint8, erro
 			&nlri.PathIdentifier,
 		})
 		if err != nil {
-			return nil, consumed, fmt.Errorf("Unable to decode path identifier: %v", err)
+			return nil, consumed, errors.Wrap(err, "Unable to decode path identifier")
 		}
 
 		consumed += pathIdentifierLen
diff --git a/protocols/bgp/packet/path_attributes.go b/protocols/bgp/packet/path_attributes.go
index a09a3e2c81a5e130c4f59fe769f6ed4432db87f1..6c312fdd5465eaf3b0a62211b94a17a8bf4353de 100644
--- a/protocols/bgp/packet/path_attributes.go
+++ b/protocols/bgp/packet/path_attributes.go
@@ -9,6 +9,7 @@ import (
 	"github.com/bio-routing/bio-rd/protocols/bgp/types"
 	"github.com/bio-routing/bio-rd/route"
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -23,7 +24,7 @@ func decodePathAttrs(buf *bytes.Buffer, tpal uint16, opt *DecodeOptions) (*PathA
 	for p < tpal {
 		pa, consumed, err = decodePathAttr(buf, opt)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode path attr: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode path attr")
 		}
 		p += consumed
 
@@ -44,7 +45,7 @@ func decodePathAttr(buf *bytes.Buffer, opt *DecodeOptions) (pa *PathAttribute, c
 
 	err = decodePathAttrFlags(buf, pa)
 	if err != nil {
-		return nil, consumed, fmt.Errorf("Unable to get path attribute flags: %v", err)
+		return nil, consumed, errors.Wrap(err, "Unable to get path attribute flags")
 	}
 	consumed++
 
@@ -63,7 +64,7 @@ func decodePathAttr(buf *bytes.Buffer, opt *DecodeOptions) (pa *PathAttribute, c
 	switch pa.TypeCode {
 	case OriginAttr:
 		if err := pa.decodeOrigin(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode Origin: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode Origin")
 		}
 	case ASPathAttr:
 		asnLength := uint8(2)
@@ -72,62 +73,62 @@ func decodePathAttr(buf *bytes.Buffer, opt *DecodeOptions) (pa *PathAttribute, c
 		}
 
 		if err := pa.decodeASPath(buf, asnLength); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode AS Path: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode AS Path")
 		}
 	/* Don't decodeAS4Paths yet: The rest of the software does not support it right yet!
 	case AS4PathAttr:
 		if err := pa.decodeASPath(buf, 4); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode AS4 Path: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode AS4 Path")
 		}*/
 	case NextHopAttr:
 		if err := pa.decodeNextHop(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode Next-Hop: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode Next-Hop")
 		}
 	case MEDAttr:
 		if err := pa.decodeMED(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode MED: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode MED")
 		}
 	case LocalPrefAttr:
 		if err := pa.decodeLocalPref(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode local pref: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode local pref")
 		}
 	case AggregatorAttr:
 		if err := pa.decodeAggregator(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode Aggregator: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode Aggregator")
 		}
 	case AtomicAggrAttr:
 		// Nothing to do for 0 octet long attribute
 	case CommunitiesAttr:
 		if err := pa.decodeCommunities(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode Community: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode Community")
 		}
 	case OriginatorIDAttr:
 		if err := pa.decodeOriginatorID(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode OriginatorID: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode OriginatorID")
 		}
 	case ClusterListAttr:
 		if err := pa.decodeClusterList(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode OriginatorID: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode OriginatorID")
 		}
 	case MultiProtocolReachNLRICode:
 		if err := pa.decodeMultiProtocolReachNLRI(buf, opt.AddPath); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to multi protocol reachable NLRI: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to multi protocol reachable NLRI")
 		}
 	case MultiProtocolUnreachNLRICode:
 		if err := pa.decodeMultiProtocolUnreachNLRI(buf, opt.AddPath); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to multi protocol unreachable NLRI: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to multi protocol unreachable NLRI")
 		}
 	case AS4AggregatorAttr:
 		if err := pa.decodeAS4Aggregator(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to skip not supported AS4Aggregator: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to skip not supported AS4Aggregator")
 		}
 	case LargeCommunitiesAttr:
 		if err := pa.decodeLargeCommunities(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode large communities: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode large communities")
 		}
 	default:
 		if err := pa.decodeUnknown(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode unknown attribute: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode unknown attribute")
 		}
 	}
 
@@ -138,7 +139,7 @@ func (pa *PathAttribute) decodeMultiProtocolReachNLRI(buf *bytes.Buffer, addPath
 	b := make([]byte, pa.Length)
 	n, err := buf.Read(b)
 	if err != nil {
-		return fmt.Errorf("Unable to read %d bytes from buffer: %v", pa.Length, err)
+		return errors.Wrapf(err, "Unable to read %d bytes from buffer", pa.Length)
 	}
 	if n != int(pa.Length) {
 		return fmt.Errorf("Unable to read %d bytes from buffer, only got %d bytes", pa.Length, n)
@@ -146,7 +147,7 @@ func (pa *PathAttribute) decodeMultiProtocolReachNLRI(buf *bytes.Buffer, addPath
 
 	nlri, err := deserializeMultiProtocolReachNLRI(b, addPath)
 	if err != nil {
-		return fmt.Errorf("Unable to decode MP_REACH_NLRI: %v", err)
+		return errors.Wrap(err, "Unable to decode MP_REACH_NLRI")
 	}
 
 	pa.Value = nlri
@@ -157,7 +158,7 @@ func (pa *PathAttribute) decodeMultiProtocolUnreachNLRI(buf *bytes.Buffer, addPa
 	b := make([]byte, pa.Length)
 	n, err := buf.Read(b)
 	if err != nil {
-		return fmt.Errorf("Unable to read %d bytes from buffer: %v", pa.Length, err)
+		return errors.Wrapf(err, "Unable to read %d bytes from buffer", pa.Length)
 	}
 	if n != int(pa.Length) {
 		return fmt.Errorf("Unable to read %d bytes from buffer, only got %d bytes", pa.Length, n)
@@ -165,7 +166,7 @@ func (pa *PathAttribute) decodeMultiProtocolUnreachNLRI(buf *bytes.Buffer, addPa
 
 	nlri, err := deserializeMultiProtocolUnreachNLRI(b, addPath)
 	if err != nil {
-		return fmt.Errorf("Unable to decode MP_UNREACH_NLRI: %v", err)
+		return errors.Wrap(err, "Unable to decode MP_UNREACH_NLRI")
 	}
 
 	pa.Value = nlri
@@ -177,7 +178,7 @@ func (pa *PathAttribute) decodeUnknown(buf *bytes.Buffer) error {
 
 	err := decode.Decode(buf, []interface{}{&u})
 	if err != nil {
-		return fmt.Errorf("Unable to decode: %v", err)
+		return errors.Wrap(err, "Unable to decode")
 	}
 
 	pa.Value = u
@@ -190,7 +191,7 @@ func (pa *PathAttribute) decodeOrigin(buf *bytes.Buffer) error {
 	p := uint16(0)
 	err := decode.Decode(buf, []interface{}{&origin})
 	if err != nil {
-		return fmt.Errorf("Unable to decode: %v", err)
+		return errors.Wrap(err, "Unable to decode")
 	}
 
 	pa.Value = origin
@@ -269,7 +270,7 @@ func (pa *PathAttribute) decodeNextHop(buf *bytes.Buffer) error {
 	nextHop := uint32(0)
 	err := decode.Decode(buf, []interface{}{&nextHop})
 	if err != nil {
-		return fmt.Errorf("Unable to decode next hop: %v", err)
+		return errors.Wrap(err, "Unable to decode next hop")
 	}
 
 	pa.Value = bnet.IPv4(nextHop)
@@ -360,7 +361,7 @@ func (pa *PathAttribute) decodeAS4Aggregator(buf *bytes.Buffer) error {
 func (pa *PathAttribute) decodeUint32(buf *bytes.Buffer, attrName string) error {
 	v, err := read4BytesAsUint32(buf)
 	if err != nil {
-		return fmt.Errorf("Unable to decode %s: %v", attrName, err)
+		return errors.Wrapf(err, "Unable to decode %s", attrName)
 	}
 
 	pa.Value = v
@@ -368,7 +369,7 @@ func (pa *PathAttribute) decodeUint32(buf *bytes.Buffer, attrName string) error
 	p := uint16(4)
 	err = dumpNBytes(buf, pa.Length-p)
 	if err != nil {
-		return fmt.Errorf("dumpNBytes failed: %v", err)
+		return errors.Wrap(err, "dumpNBytes failed")
 	}
 
 	return nil
diff --git a/protocols/bgp/server/bmp_router.go b/protocols/bgp/server/bmp_router.go
index 84f5c668508137ea3ab13ed93e7051b2d282e0d7..ff01369b1092c3370c1138863bf3d52df3eea2a5 100644
--- a/protocols/bgp/server/bmp_router.go
+++ b/protocols/bgp/server/bmp_router.go
@@ -13,6 +13,7 @@ import (
 	"github.com/bio-routing/bio-rd/routingtable"
 	"github.com/bio-routing/bio-rd/routingtable/filter"
 	"github.com/bio-routing/bio-rd/routingtable/locRIB"
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 	"github.com/taktv6/tflow2/convert"
 )
@@ -280,7 +281,7 @@ func (r *router) processPeerUpNotification(msg *bmppkt.PeerUpNotification) error
 
 	sentOpen, err := packet.DecodeOpenMsg(bytes.NewBuffer(msg.SentOpenMsg[packet.HeaderLen:]))
 	if err != nil {
-		return fmt.Errorf("Unable to decode sent open message sent from %v to %v: %v", r.address.String(), msg.PerPeerHeader.PeerAddress, err)
+		return errors.Wrapf(err, "Unable to decode sent open message sent from %v to %v", r.address.String(), msg.PerPeerHeader.PeerAddress)
 	}
 
 	if len(msg.ReceivedOpenMsg) < packet.MinOpenLen {
@@ -289,7 +290,7 @@ func (r *router) processPeerUpNotification(msg *bmppkt.PeerUpNotification) error
 
 	recvOpen, err := packet.DecodeOpenMsg(bytes.NewBuffer(msg.ReceivedOpenMsg[packet.HeaderLen:]))
 	if err != nil {
-		return fmt.Errorf("Unable to decode received open message sent from %v to %v: %v", msg.PerPeerHeader.PeerAddress, r.address.String(), err)
+		return errors.Wrapf(err, "Unable to decode received open message sent from %v to %v", msg.PerPeerHeader.PeerAddress, r.address.String())
 	}
 
 	addrLen := net.IPv4len
diff --git a/protocols/bgp/server/bmp_server.go b/protocols/bgp/server/bmp_server.go
index d49355ee030d4d68b192c8ad33a7cf751f8c10cb..30916c3cb685b935a3f2132893898320c59ce61a 100644
--- a/protocols/bgp/server/bmp_server.go
+++ b/protocols/bgp/server/bmp_server.go
@@ -10,6 +10,7 @@ import (
 	bmppkt "github.com/bio-routing/bio-rd/protocols/bmp/packet"
 	"github.com/bio-routing/bio-rd/routingtable"
 	"github.com/bio-routing/bio-rd/routingtable/locRIB"
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 	"github.com/taktv6/tflow2/convert"
 )
@@ -132,7 +133,7 @@ func recvBMPMsg(c net.Conn) (msg []byte, err error) {
 	buffer := make([]byte, defaultBufferLen)
 	_, err = io.ReadFull(c, buffer[0:bmppkt.MinLen])
 	if err != nil {
-		return nil, fmt.Errorf("Read failed: %v", err)
+		return nil, errors.Wrap(err, "Read failed")
 	}
 
 	l := convert.Uint32b(buffer[1:5])
@@ -145,7 +146,7 @@ func recvBMPMsg(c net.Conn) (msg []byte, err error) {
 	toRead := l
 	_, err = io.ReadFull(c, buffer[bmppkt.MinLen:toRead])
 	if err != nil {
-		return nil, fmt.Errorf("Read failed: %v", err)
+		return nil, errors.Wrap(err, "Read failed")
 	}
 
 	return buffer[0:toRead], nil
diff --git a/protocols/bgp/server/fsm.go b/protocols/bgp/server/fsm.go
index 6e11d6672aed81061d870e79c71183066e35a53e..2d1d3ce03c5ae7d3ff77198799440c6bf58e5ff1 100644
--- a/protocols/bgp/server/fsm.go
+++ b/protocols/bgp/server/fsm.go
@@ -9,6 +9,7 @@ import (
 	"time"
 
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 )
 
@@ -267,7 +268,7 @@ func (fsm *FSM) sendOpen() error {
 
 	_, err := fsm.con.Write(msg)
 	if err != nil {
-		return fmt.Errorf("Unable to send OPEN message: %v", err)
+		return errors.Wrap(err, "Unable to send OPEN message")
 	}
 
 	return nil
@@ -296,7 +297,7 @@ func (fsm *FSM) sendNotification(errorCode uint8, errorSubCode uint8) error {
 
 	_, err := fsm.con.Write(msg)
 	if err != nil {
-		return fmt.Errorf("Unable to send NOTIFICATION message: %v", err)
+		return errors.Wrap(err, "Unable to send NOTIFICATION message")
 	}
 
 	return nil
@@ -307,7 +308,7 @@ func (fsm *FSM) sendKeepalive() error {
 
 	_, err := fsm.con.Write(msg)
 	if err != nil {
-		return fmt.Errorf("Unable to send KEEPALIVE message: %v", err)
+		return errors.Wrap(err, "Unable to send KEEPALIVE message")
 	}
 
 	return nil
@@ -317,14 +318,14 @@ func recvMsg(c net.Conn) (msg []byte, err error) {
 	buffer := make([]byte, packet.MaxLen)
 	_, err = io.ReadFull(c, buffer[0:packet.MinLen])
 	if err != nil {
-		return nil, fmt.Errorf("Read failed: %v", err)
+		return nil, errors.Wrap(err, "Read failed")
 	}
 
 	l := int(buffer[16])*256 + int(buffer[17])
 	toRead := l
 	_, err = io.ReadFull(c, buffer[packet.MinLen:toRead])
 	if err != nil {
-		return nil, fmt.Errorf("Read failed: %v", err)
+		return nil, errors.Wrap(err, "Read failed")
 	}
 
 	return buffer, nil
diff --git a/protocols/bgp/server/fsm_established.go b/protocols/bgp/server/fsm_established.go
index 05e540b597394424a5fde51461cc2aa55e42888b..5ea39ba2158a62ff40cfe5efad9fa4632b1bb4ac 100644
--- a/protocols/bgp/server/fsm_established.go
+++ b/protocols/bgp/server/fsm_established.go
@@ -9,6 +9,7 @@ import (
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
 	"github.com/bio-routing/bio-rd/route"
 	"github.com/bio-routing/bio-rd/routingtable"
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 )
 
@@ -58,11 +59,11 @@ func (s establishedState) run() (state, string) {
 func (s *establishedState) init() error {
 	host, _, err := net.SplitHostPort(s.fsm.con.LocalAddr().String())
 	if err != nil {
-		return fmt.Errorf("Unable to get local address: %v", err)
+		return errors.Wrap(err, "Unable to get local address")
 	}
 	localAddr, err := bnet.IPFromString(host)
 	if err != nil {
-		return fmt.Errorf("Unable to parse address: %v", err)
+		return errors.Wrap(err, "Unable to parse address")
 	}
 
 	n := &routingtable.Neighbor{
diff --git a/protocols/bgp/server/server.go b/protocols/bgp/server/server.go
index 76d8ee248582824fc7b73056a88db005eb3afc26..fe8558efde956e90c2b9edaaaff3aed751f32a7d 100644
--- a/protocols/bgp/server/server.go
+++ b/protocols/bgp/server/server.go
@@ -1,12 +1,12 @@
 package server
 
 import (
-	"fmt"
 	"net"
 	"strings"
 	"sync"
 
 	"github.com/bio-routing/bio-rd/config"
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 )
 
@@ -38,7 +38,7 @@ func (b *bgpServer) RouterID() uint32 {
 
 func (b *bgpServer) Start(c *config.Global) error {
 	if err := c.SetDefaultGlobalConfigValues(); err != nil {
-		return fmt.Errorf("Failed to load defaults: %v", err)
+		return errors.Wrap(err, "Failed to load defaults")
 	}
 
 	log.Infof("ROUTER ID: %d\n", c.RouterID)
@@ -50,7 +50,7 @@ func (b *bgpServer) Start(c *config.Global) error {
 		for _, addr := range c.LocalAddressList {
 			l, err := NewTCPListener(addr, c.Port, acceptCh)
 			if err != nil {
-				return fmt.Errorf("Failed to start TCPListener for %s: %v", addr.String(), err)
+				return errors.Wrapf(err, "Failed to start TCPListener for %s", addr.String())
 			}
 			b.listeners = append(b.listeners, l)
 		}
diff --git a/protocols/bgp/server/update_helper.go b/protocols/bgp/server/update_helper.go
index a510e54e98c10e8db673b1156c26e3de1cf19f24..f8822dece7ab3b4390ec3e53cc698d8c65d3f37e 100644
--- a/protocols/bgp/server/update_helper.go
+++ b/protocols/bgp/server/update_helper.go
@@ -1,10 +1,10 @@
 package server
 
 import (
-	"fmt"
 	"io"
 
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
+	"github.com/pkg/errors"
 
 	log "github.com/sirupsen/logrus"
 )
@@ -18,7 +18,7 @@ func serializeAndSendUpdate(out io.Writer, update serializeAbleUpdate, opt *pack
 
 	_, err = out.Write(updateBytes)
 	if err != nil {
-		return fmt.Errorf("Failed sending Update: %v", err)
+		return errors.Wrap(err, "Failed sending Update")
 	}
 	return nil
 }
diff --git a/protocols/bgp/server/update_helper_test.go b/protocols/bgp/server/update_helper_test.go
index fee9d895b8d491599eeaf5f4e9ba560eee5dc848..3b8ec458dd0df0d18357ac210d4f1afacbc30d33 100644
--- a/protocols/bgp/server/update_helper_test.go
+++ b/protocols/bgp/server/update_helper_test.go
@@ -2,12 +2,12 @@ package server
 
 import (
 	"bytes"
-	"errors"
 	"io"
 	"testing"
 
 	bnet "github.com/bio-routing/bio-rd/net"
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
+	"github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -89,7 +89,12 @@ func TestSerializeAndSendUpdate(t *testing.T) {
 		t.Run(test.name, func(t *testing.T) {
 			opt := &packet.EncodeOptions{}
 			err := serializeAndSendUpdate(test.buf, test.testUpdate, opt)
-			assert.Equal(t, test.err, err)
+
+			if test.err == nil {
+				assert.NoError(t, err)
+			} else {
+				assert.Equal(t, test.err.Error(), err.Error())
+			}
 
 			assert.Equal(t, test.expected, test.buf.Bytes())
 		})
diff --git a/protocols/bmp/packet/decode.go b/protocols/bmp/packet/decode.go
index a76f6b7853e221126b77512039d9fc5296469496..4d97389ab1ed4f5c7b86b2357d8168d6e897815d 100644
--- a/protocols/bmp/packet/decode.go
+++ b/protocols/bmp/packet/decode.go
@@ -3,6 +3,8 @@ package packet
 import (
 	"bytes"
 	"fmt"
+
+	"github.com/pkg/errors"
 )
 
 const (
@@ -38,7 +40,7 @@ func Decode(msg []byte) (Msg, error) {
 
 	ch, err := decodeCommonHeader(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode common header: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode common header")
 	}
 
 	if ch.Version != BMPVersion {
@@ -49,49 +51,49 @@ func Decode(msg []byte) (Msg, error) {
 	case RouteMonitoringType:
 		rm, err := decodeRouteMonitoringMsg(buf, ch)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode route monitoring message: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode route monitoring message")
 		}
 
 		return rm, err
 	case StatisticsReportType:
 		sr, err := decodeStatsReport(buf, ch)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode stats report: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode stats report")
 		}
 
 		return sr, nil
 	case PeerDownNotificationType:
 		pd, err := decodePeerDownNotification(buf, ch)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode peer down notification: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode peer down notification")
 		}
 
 		return pd, nil
 	case PeerUpNotificationType:
 		pu, err := decodePeerUpNotification(buf, ch)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode peer up notification: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode peer up notification")
 		}
 
 		return pu, nil
 	case InitiationMessageType:
 		im, err := decodeInitiationMessage(buf, ch)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode initiation message: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode initiation message")
 		}
 
 		return im, nil
 	case TerminationMessageType:
 		tm, err := decodeTerminationMessage(buf, ch)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode termination message: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode termination message")
 		}
 
 		return tm, nil
 	case RouteMirroringMessageType:
 		rm, err := decodeRouteMirroringMsg(buf, ch)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode route mirroring message: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode route mirroring message")
 		}
 
 		return rm, nil
diff --git a/protocols/bmp/packet/initiation_message.go b/protocols/bmp/packet/initiation_message.go
index 6fbc3f30c2c0f09e178b981964661990425ca597..896599d5f45a0dd6f6a029fcabc5c63cdee9fcf3 100644
--- a/protocols/bmp/packet/initiation_message.go
+++ b/protocols/bmp/packet/initiation_message.go
@@ -2,7 +2,8 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
+
+	"github.com/pkg/errors"
 )
 
 // InitiationMessage represents an initiation message
@@ -28,7 +29,7 @@ func decodeInitiationMessage(buf *bytes.Buffer, ch *CommonHeader) (Msg, error) {
 	for read < toRead {
 		tlv, err := decodeInformationTLV(buf)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode TLV: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode TLV")
 		}
 
 		im.TLVs = append(im.TLVs, tlv)
diff --git a/protocols/bmp/packet/peer_down.go b/protocols/bmp/packet/peer_down.go
index 7b0303043f489f93ce4c1ed4cc2610cbb87fa9e2..c81d46f905c94b33a24f5a8b3bdd69fc531cdb39 100644
--- a/protocols/bmp/packet/peer_down.go
+++ b/protocols/bmp/packet/peer_down.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decoder"
+	"github.com/pkg/errors"
 )
 
 const (
@@ -32,7 +32,7 @@ func decodePeerDownNotification(buf *bytes.Buffer, ch *CommonHeader) (*PeerDownN
 
 	pph, err := decodePerPeerHeader(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode per peer header: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode per peer header")
 	}
 
 	p.PerPeerHeader = pph
@@ -57,7 +57,7 @@ func decodePeerDownNotification(buf *bytes.Buffer, ch *CommonHeader) (*PeerDownN
 
 	err = decoder.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to read Data: %v", err)
+		return nil, errors.Wrap(err, "Unable to read Data")
 	}
 
 	return p, nil
diff --git a/protocols/bmp/packet/peer_up.go b/protocols/bmp/packet/peer_up.go
index 34d37a7cbc9786ec4459b50a56c917a037c261a4..c0e4433745023143480a08deab80d74a3dfda63c 100644
--- a/protocols/bmp/packet/peer_up.go
+++ b/protocols/bmp/packet/peer_up.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decoder"
+	"github.com/pkg/errors"
 )
 
 const (
@@ -36,7 +36,7 @@ func decodePeerUpNotification(buf *bytes.Buffer, ch *CommonHeader) (*PeerUpNotif
 
 	pph, err := decodePerPeerHeader(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode per peer header: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode per peer header")
 	}
 
 	p.PerPeerHeader = pph
@@ -54,13 +54,13 @@ func decodePeerUpNotification(buf *bytes.Buffer, ch *CommonHeader) (*PeerUpNotif
 
 	sentOpenMsg, err := getOpenMsg(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to get OPEN message: %v", err)
+		return nil, errors.Wrap(err, "Unable to get OPEN message")
 	}
 	p.SentOpenMsg = sentOpenMsg
 
 	recvOpenMsg, err := getOpenMsg(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to get OPEN message: %v", err)
+		return nil, errors.Wrap(err, "Unable to get OPEN message")
 	}
 	p.ReceivedOpenMsg = recvOpenMsg
 
@@ -87,7 +87,7 @@ func getOpenMsg(buf *bytes.Buffer) ([]byte, error) {
 	}
 	err := decoder.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to read: %v", err)
+		return nil, errors.Wrap(err, "Unable to read")
 	}
 
 	if msg[OpenMsgMinLen-1] == 0 {
@@ -101,7 +101,7 @@ func getOpenMsg(buf *bytes.Buffer) ([]byte, error) {
 
 	err = decoder.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to read: %v", err)
+		return nil, errors.Wrap(err, "Unable to read")
 	}
 
 	msg = append(msg, optParams...)
diff --git a/protocols/bmp/packet/route_mirroring.go b/protocols/bmp/packet/route_mirroring.go
index e3d013a0f1d86248996613525236b58c88ab09ca..9ad2fe49fc2b33fe0308f50a7d237da616da908c 100644
--- a/protocols/bmp/packet/route_mirroring.go
+++ b/protocols/bmp/packet/route_mirroring.go
@@ -2,7 +2,8 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
+
+	"github.com/pkg/errors"
 )
 
 // RouteMirroringMsg represents a route mirroring message
@@ -24,7 +25,7 @@ func decodeRouteMirroringMsg(buf *bytes.Buffer, ch *CommonHeader) (*RouteMirrori
 
 	pph, err := decodePerPeerHeader(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode per peer header: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode per peer header")
 	}
 
 	rm.PerPeerHeader = pph
@@ -35,7 +36,7 @@ func decodeRouteMirroringMsg(buf *bytes.Buffer, ch *CommonHeader) (*RouteMirrori
 	for read < toRead {
 		tlv, err := decodeInformationTLV(buf)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode TLV: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode TLV")
 		}
 
 		rm.TLVs = append(rm.TLVs, tlv)
diff --git a/protocols/bmp/packet/route_monitoring.go b/protocols/bmp/packet/route_monitoring.go
index d76aa453fd9ecb5869f4f6e1436db4db83029eee..8f69c64ce211fa1af382ec3b40c37cb465422eb5 100644
--- a/protocols/bmp/packet/route_monitoring.go
+++ b/protocols/bmp/packet/route_monitoring.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decoder"
+	"github.com/pkg/errors"
 )
 
 // RouteMonitoringMsg represents a Route Monitoring Message
@@ -26,7 +26,7 @@ func decodeRouteMonitoringMsg(buf *bytes.Buffer, ch *CommonHeader) (*RouteMonito
 
 	pph, err := decodePerPeerHeader(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode per peer header: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode per peer header")
 	}
 
 	rm.PerPeerHeader = pph
diff --git a/protocols/bmp/packet/stats_report.go b/protocols/bmp/packet/stats_report.go
index 3fa53995a48e6217a59a5a7ea7369dc71fc084a8..f9a9709cc055008d0baae2d91b971df1a91487af 100644
--- a/protocols/bmp/packet/stats_report.go
+++ b/protocols/bmp/packet/stats_report.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decoder"
+	"github.com/pkg/errors"
 )
 
 // StatsReport represents a stats report message
@@ -27,7 +27,7 @@ func decodeStatsReport(buf *bytes.Buffer, ch *CommonHeader) (Msg, error) {
 
 	pph, err := decodePerPeerHeader(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode per peer header: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode per peer header")
 	}
 
 	sr.PerPeerHeader = pph
@@ -45,7 +45,7 @@ func decodeStatsReport(buf *bytes.Buffer, ch *CommonHeader) (Msg, error) {
 	for i := uint32(0); i < sr.StatsCount; i++ {
 		infoTLV, err := decodeInformationTLV(buf)
 		if err != nil {
-			return sr, fmt.Errorf("Unable to decode information TLV: %v", err)
+			return sr, errors.Wrap(err, "Unable to decode information TLV")
 		}
 
 		sr.Stats[i] = infoTLV
diff --git a/protocols/bmp/packet/termination_message.go b/protocols/bmp/packet/termination_message.go
index 8021fbebacfce9b8f642c2493fedd39acc9a45f6..e4ff98356493b4b781413ace6a7fdba57b2f9a20 100644
--- a/protocols/bmp/packet/termination_message.go
+++ b/protocols/bmp/packet/termination_message.go
@@ -2,7 +2,8 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
+
+	"github.com/pkg/errors"
 )
 
 // TerminationMessage represents a termination message
@@ -28,7 +29,7 @@ func decodeTerminationMessage(buf *bytes.Buffer, ch *CommonHeader) (*Termination
 	for read < toRead {
 		tlv, err := decodeInformationTLV(buf)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode TLV: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode TLV")
 		}
 
 		tm.TLVs = append(tm.TLVs, tlv)
diff --git a/protocols/bmp/server/server.go b/protocols/bmp/server/server.go
index 2415929aaa1c7f92e6ba7e7d2683b1d8d496764a..50cccf15a88c7ea4f91d1872507c2ca39dde0f90 100644
--- a/protocols/bmp/server/server.go
+++ b/protocols/bmp/server/server.go
@@ -9,6 +9,7 @@ import (
 
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
 	"github.com/bio-routing/bio-rd/routingtable/locRIB"
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 	"github.com/taktv6/tflow2/convert"
 )
@@ -70,7 +71,7 @@ func recvMsg(c net.Conn) (msg []byte, err error) {
 	buffer := make([]byte, defaultBufferLen)
 	_, err = io.ReadFull(c, buffer[0:packet.MinLen])
 	if err != nil {
-		return nil, fmt.Errorf("Read failed: %v", err)
+		return nil, errors.Wrap(err, "Read failed")
 	}
 
 	l := convert.Uint32b(buffer[1:3])
@@ -83,7 +84,7 @@ func recvMsg(c net.Conn) (msg []byte, err error) {
 	toRead := l
 	_, err = io.ReadFull(c, buffer[packet.MinLen:toRead])
 	if err != nil {
-		return nil, fmt.Errorf("Read failed: %v", err)
+		return nil, errors.Wrap(err, "Read failed")
 	}
 
 	return buffer, nil
diff --git a/protocols/device/server.go b/protocols/device/server.go
index 22eeb29d3914d9cf0ec100b4970ae576c406af1e..00e29266830a87543505c8e0592d724afdbd9ba2 100644
--- a/protocols/device/server.go
+++ b/protocols/device/server.go
@@ -1,8 +1,9 @@
 package device
 
 import (
-	"fmt"
 	"sync"
+
+	"github.com/pkg/errors"
 )
 
 // Server represents a device server
@@ -29,7 +30,7 @@ func New() (*Server, error) {
 	srv := newWithAdapter(nil)
 	err := srv.loadAdapter()
 	if err != nil {
-		return nil, fmt.Errorf("Unable to create OS adapter: %v", err)
+		return nil, errors.Wrap(err, "Unable to create OS adapter")
 	}
 
 	return srv, nil
@@ -48,7 +49,7 @@ func newWithAdapter(a osAdapter) *Server {
 func (ds *Server) Start() error {
 	err := ds.osAdapter.start()
 	if err != nil {
-		return fmt.Errorf("Unable to start osAdapter: %v", err)
+		return errors.Wrap(err, "Unable to start osAdapter")
 	}
 
 	return nil
diff --git a/protocols/device/server_linux.go b/protocols/device/server_linux.go
index fa344d817aba04c01af0c433996c14b04c5ec729..31bc93fa3102d1793c5b8d959173837a32277616 100644
--- a/protocols/device/server_linux.go
+++ b/protocols/device/server_linux.go
@@ -1,9 +1,8 @@
 package device
 
 import (
-	"fmt"
-
 	bnet "github.com/bio-routing/bio-rd/net"
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 	"github.com/vishvananda/netlink"
 )
@@ -11,7 +10,7 @@ import (
 func (ds *Server) loadAdapter() error {
 	a, err := newOSAdapterLinux(ds)
 	if err != nil {
-		return fmt.Errorf("Unable to create linux adapter: %v", err)
+		return errors.Wrap(err, "Unable to create linux adapter")
 	}
 
 	ds.osAdapter = a
@@ -31,7 +30,7 @@ func newOSAdapterLinux(srv *Server) (*osAdapterLinux, error) {
 
 	h, err := netlink.NewHandle()
 	if err != nil {
-		return nil, fmt.Errorf("Failed to create netlink handle: %v", err)
+		return nil, errors.Wrap(err, "Failed to create netlink handle")
 	}
 
 	o.handle = h
@@ -42,18 +41,18 @@ func (o *osAdapterLinux) start() error {
 	chLU := make(chan netlink.LinkUpdate)
 	err := netlink.LinkSubscribe(chLU, o.done)
 	if err != nil {
-		return fmt.Errorf("Unable to subscribe for link updates: %v", err)
+		return errors.Wrap(err, "Unable to subscribe for link updates")
 	}
 
 	chAU := make(chan netlink.AddrUpdate)
 	err = netlink.AddrSubscribe(chAU, o.done)
 	if err != nil {
-		return fmt.Errorf("Unable to subscribe for address updates: %v", err)
+		return errors.Wrap(err, "Unable to subscribe for address updates")
 	}
 
 	err = o.init()
 	if err != nil {
-		return fmt.Errorf("Init failed: %v", err)
+		return errors.Wrap(err, "Init failed")
 	}
 
 	go o.monitorLinks(chLU)
@@ -65,7 +64,7 @@ func (o *osAdapterLinux) start() error {
 func (o *osAdapterLinux) init() error {
 	links, err := o.handle.LinkList()
 	if err != nil {
-		return fmt.Errorf("Unable to get links: %v", err)
+		return errors.Wrap(err, "Unable to get links")
 	}
 
 	for _, l := range links {
@@ -74,7 +73,7 @@ func (o *osAdapterLinux) init() error {
 		for _, f := range []int{4, 6} {
 			addrs, err := o.handle.AddrList(l, f)
 			if err != nil {
-				return fmt.Errorf("Unable to get addresses for interface %s: %v", d.Name, err)
+				return errors.Wrapf(err, "Unable to get addresses for interface %s", d.Name)
 			}
 
 			for _, addr := range addrs {
diff --git a/protocols/isis/packet/csnp.go b/protocols/isis/packet/csnp.go
index c528a8fb3031446f8a85d80f0ac6e1e0912aa204..ae6eaf73c2bb962c3ef581de818d2d574ca473a8 100644
--- a/protocols/isis/packet/csnp.go
+++ b/protocols/isis/packet/csnp.go
@@ -2,13 +2,13 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 	"math"
 	"sort"
 
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
 	"github.com/bio-routing/bio-rd/util/decode"
 	umath "github.com/bio-routing/bio-rd/util/math"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -133,7 +133,7 @@ func DecodeCSNP(buf *bytes.Buffer) (*CSNP, error) {
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	nEntries := (csnp.PDULength - CSNPMinLen) / LSPEntryLen
@@ -141,7 +141,7 @@ func DecodeCSNP(buf *bytes.Buffer) (*CSNP, error) {
 	for i := uint16(0); i < nEntries; i++ {
 		lspEntry, err := decodeLSPEntry(buf)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to get LSPEntries: %v", err)
+			return nil, errors.Wrap(err, "Unable to get LSPEntries")
 		}
 		csnp.LSPEntries[i] = *lspEntry
 	}
diff --git a/protocols/isis/packet/header.go b/protocols/isis/packet/header.go
index ca627d2da1597c5069a8c4a774b51d931b2deb74..8ff00ed2c4fc16987bc557e7ac10ef9fc93b9061 100644
--- a/protocols/isis/packet/header.go
+++ b/protocols/isis/packet/header.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 )
 
 // ISISHeader represents an ISIS header
@@ -42,7 +42,7 @@ func DecodeHeader(buf *bytes.Buffer) (*ISISHeader, error) {
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	return h, nil
diff --git a/protocols/isis/packet/hello.go b/protocols/isis/packet/hello.go
index 07dc9dc5fbd860027b8d8aa3c843c26cf58ed9c3..e6170f9bbf8cdaaa953cb27293142e0134106767 100644
--- a/protocols/isis/packet/hello.go
+++ b/protocols/isis/packet/hello.go
@@ -2,10 +2,10 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -63,12 +63,12 @@ func DecodeP2PHello(buf *bytes.Buffer) (*P2PHello, error) {
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	TLVs, err := readTLVs(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to read TLVs: %v", err)
+		return nil, errors.Wrap(err, "Unable to read TLVs")
 	}
 
 	pdu.TLVs = TLVs
@@ -91,12 +91,12 @@ func DecodeL2Hello(buf *bytes.Buffer) (*L2Hello, error) {
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	TLVs, err := readTLVs(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to read TLVs: %v", err)
+		return nil, errors.Wrap(err, "Unable to read TLVs")
 	}
 
 	pdu.TLVs = TLVs
diff --git a/protocols/isis/packet/isis.go b/protocols/isis/packet/isis.go
index 71aee6ccc8a59f99f449413ed736081057bd7b06..d433cd987334314560aad0ae9f8f8948e85ff71a 100644
--- a/protocols/isis/packet/isis.go
+++ b/protocols/isis/packet/isis.go
@@ -2,7 +2,8 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
+
+	"github.com/pkg/errors"
 )
 
 const (
@@ -33,7 +34,7 @@ func Decode(buf *bytes.Buffer) (*ISISPacket, error) {
 
 	hdr, err := DecodeHeader(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode header: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode header")
 	}
 	pkt.Header = hdr
 
@@ -41,7 +42,7 @@ func Decode(buf *bytes.Buffer) (*ISISPacket, error) {
 	case P2P_HELLO:
 		p2pHello, err := DecodeP2PHello(buf)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode P2P hello: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode P2P hello")
 		}
 		pkt.Body = p2pHello
 	}
diff --git a/protocols/isis/packet/lsp.go b/protocols/isis/packet/lsp.go
index 0fe4b689344dd58585013829d795b5072df51ae1..39104ed7815b8a9c8add738eec26696a30377953 100644
--- a/protocols/isis/packet/lsp.go
+++ b/protocols/isis/packet/lsp.go
@@ -2,11 +2,11 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/FMNSSun/libhash/fletcher"
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -80,12 +80,12 @@ func DecodeLSPDU(buf *bytes.Buffer) (*LSPDU, error) {
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	TLVs, err := readTLVs(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to read TLVs: %v", err)
+		return nil, errors.Wrap(err, "Unable to read TLVs")
 	}
 
 	pdu.TLVs = TLVs
diff --git a/protocols/isis/packet/lsp_entry.go b/protocols/isis/packet/lsp_entry.go
index 8b4afa5554dbba46245ab2b010dafbc2ab282fe2..d9bc599da8a429155aa5f9cb7455a249a751f5c8 100644
--- a/protocols/isis/packet/lsp_entry.go
+++ b/protocols/isis/packet/lsp_entry.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -42,7 +42,7 @@ func decodeLSPEntry(buf *bytes.Buffer) (*LSPEntry, error) {
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	return lspEntry, nil
diff --git a/protocols/isis/packet/psnp.go b/protocols/isis/packet/psnp.go
index 0686a6b8ccaaef29581bcfb71052f92a7f60cb64..82ade8286572ffdf035b3c75f0cf315ade56fe78 100644
--- a/protocols/isis/packet/psnp.go
+++ b/protocols/isis/packet/psnp.go
@@ -2,12 +2,12 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 	"math"
 
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
 	"github.com/bio-routing/bio-rd/util/decode"
 	umath "github.com/bio-routing/bio-rd/util/math"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -81,7 +81,7 @@ func DecodePSNP(buf *bytes.Buffer) (*PSNP, error) {
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	nEntries := (psnp.PDULength - PSNPMinLen) / LSPEntryLen
@@ -89,7 +89,7 @@ func DecodePSNP(buf *bytes.Buffer) (*PSNP, error) {
 	for i := uint16(0); i < nEntries; i++ {
 		lspEntry, err := decodeLSPEntry(buf)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to get LSPEntries: %v", err)
+			return nil, errors.Wrap(err, "Unable to get LSPEntries")
 		}
 		psnp.LSPEntries[i] = *lspEntry
 	}
diff --git a/protocols/isis/packet/tlv.go b/protocols/isis/packet/tlv.go
index 6fcd8796e8cb5c9db845a91a3f1e3898567949e8..72064a481f8a317d44b98cc1533f2744b879553e 100644
--- a/protocols/isis/packet/tlv.go
+++ b/protocols/isis/packet/tlv.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 )
 
 // TLV is an interface that all TLVs must fulfill
@@ -42,7 +42,7 @@ func readTLVs(buf *bytes.Buffer) ([]TLV, error) {
 	for read < uint16(length) {
 		err = decode.Decode(buf, headFields)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode fields: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode fields")
 		}
 
 		read += 2
@@ -69,7 +69,7 @@ func readTLVs(buf *bytes.Buffer) ([]TLV, error) {
 		}
 
 		if err != nil {
-			return nil, fmt.Errorf("Unable to read TLV: %v", err)
+			return nil, errors.Wrap(err, "Unable to read TLV")
 		}
 		TLVs = append(TLVs, tlv)
 	}
diff --git a/protocols/isis/packet/tlv_area_addresses.go b/protocols/isis/packet/tlv_area_addresses.go
index 06494998163f36c35428de264e9263a915cf715b..35ba0d792ffc92e5c1098c8ca61c3e2990b1ff34 100644
--- a/protocols/isis/packet/tlv_area_addresses.go
+++ b/protocols/isis/packet/tlv_area_addresses.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
+	"github.com/pkg/errors"
 )
 
 // AreaAddressesTLVType is the type value of an area address TLV
@@ -29,14 +29,14 @@ func readAreaAddressesTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (*A
 	for read < tlvLength {
 		areaLen, err := buf.ReadByte()
 		if err != nil {
-			return nil, fmt.Errorf("Unable to read: %v", err)
+			return nil, errors.Wrap(err, "Unable to read")
 		}
 		read++
 
 		newArea := make(types.AreaID, areaLen)
 		_, err = buf.Read(newArea)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to read: %v", err)
+			return nil, errors.Wrap(err, "Unable to read")
 		}
 		read += areaLen
 
diff --git a/protocols/isis/packet/tlv_checksum.go b/protocols/isis/packet/tlv_checksum.go
index 7adc5e8624b7cef19cf944e0657b4c72013d7705..05a55f647fc4c2e208e280ac9aac9b54289dc411 100644
--- a/protocols/isis/packet/tlv_checksum.go
+++ b/protocols/isis/packet/tlv_checksum.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -45,7 +45,7 @@ func readChecksumTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (*Checks
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	return pdu, nil
diff --git a/protocols/isis/packet/tlv_dynamic_hostname.go b/protocols/isis/packet/tlv_dynamic_hostname.go
index 2b5114e948aef784d74bdf51642619d582722433..39a2a80bd86aa0090d81285a5dc0ed87eba979ff 100644
--- a/protocols/isis/packet/tlv_dynamic_hostname.go
+++ b/protocols/isis/packet/tlv_dynamic_hostname.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 )
 
 // DynamicHostNameTLVType is the type value of dynamic hostname TLV
@@ -45,7 +45,7 @@ func readDynamicHostnameTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	return pdu, nil
diff --git a/protocols/isis/packet/tlv_ip_interface_address.go b/protocols/isis/packet/tlv_ip_interface_address.go
index 012688a8b9e049513fa4398e1897b288a22fc5b4..d34e0051488d9c0d8c7710eb0c015b1f3013cff1 100644
--- a/protocols/isis/packet/tlv_ip_interface_address.go
+++ b/protocols/isis/packet/tlv_ip_interface_address.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -39,7 +39,7 @@ func readIPInterfaceAddressTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	return pdu, nil
diff --git a/protocols/isis/packet/tlv_is_neighbors.go b/protocols/isis/packet/tlv_is_neighbors.go
index 1296fee65da74f6dc3ca707521583bf83dee0253..a39db37ef78612473eb1e629ade182425ee0e5be 100644
--- a/protocols/isis/packet/tlv_is_neighbors.go
+++ b/protocols/isis/packet/tlv_is_neighbors.go
@@ -2,10 +2,10 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 )
 
 // ISNeighborsTLVType is the type value of an IS Neighbor TLV
@@ -32,7 +32,7 @@ func readISNeighborsTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (*ISN
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	return pdu, nil
diff --git a/protocols/isis/packet/tlv_p2p_adj_state.go b/protocols/isis/packet/tlv_p2p_adj_state.go
index c4b434adbb48750bce3ae686e157d27066cdf430..ec47038ab8be32b9fa640ae11a6265f6dca2916d 100644
--- a/protocols/isis/packet/tlv_p2p_adj_state.go
+++ b/protocols/isis/packet/tlv_p2p_adj_state.go
@@ -2,10 +2,10 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -52,7 +52,7 @@ func readP2PAdjacencyStateTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8)
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	return pdu, nil
diff --git a/protocols/isis/packet/tlv_protocols_supported.go b/protocols/isis/packet/tlv_protocols_supported.go
index a9597e155d539245a2c0e7fc158bb81311ac8c45..7aafbf95af6af9555f180df740f9b86b4633416b 100644
--- a/protocols/isis/packet/tlv_protocols_supported.go
+++ b/protocols/isis/packet/tlv_protocols_supported.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 )
 
 // ProtocolsSupportedTLVType is the type value of an protocols supported TLV
@@ -32,7 +32,7 @@ func readProtocolsSupportedTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8
 	for i := uint8(0); i < tlvLength; i++ {
 		err := decode.Decode(buf, fields)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode fields: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode fields")
 		}
 		pdu.NetworkLayerProtocolIDs[i] = protoID
 	}
diff --git a/protocols/isis/packet/tlv_unknown.go b/protocols/isis/packet/tlv_unknown.go
index 9488ac1ff700e6e15ee8c06256b4b16af206f2a9..08e8ae35fb254ebdcf5e09d926f0c8a83ed1f8e4 100644
--- a/protocols/isis/packet/tlv_unknown.go
+++ b/protocols/isis/packet/tlv_unknown.go
@@ -3,6 +3,8 @@ package packet
 import (
 	"bytes"
 	"fmt"
+
+	"github.com/pkg/errors"
 )
 
 // UnknownTLV represents an unknown TLV
@@ -21,7 +23,7 @@ func readUnknownTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (*Unknown
 
 	n, err := buf.Read(pdu.TLVValue)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to read: %v", err)
+		return nil, errors.Wrap(err, "Unable to read")
 	}
 
 	if n != int(tlvLength) {
diff --git a/protocols/netlink/netlink_writer.go b/protocols/netlink/netlink_writer.go
index f0fb324b8f66fd0f859dab51b58ef1f4f085e2d3..fae9a1fdd78a6b7285213fb3984fd7bb2c7532d0 100644
--- a/protocols/netlink/netlink_writer.go
+++ b/protocols/netlink/netlink_writer.go
@@ -9,6 +9,7 @@ import (
 	"github.com/bio-routing/bio-rd/route"
 	"github.com/bio-routing/bio-rd/routingtable"
 	"github.com/bio-routing/bio-rd/routingtable/filter"
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 	"github.com/vishvananda/netlink"
 )
@@ -144,7 +145,7 @@ func (nw *NetlinkWriter) addKernel(pfx bnet.Prefix) error {
 	err = netlink.RouteAdd(route)
 	if err != nil {
 		log.Errorf("Error while adding route: %v", err)
-		return fmt.Errorf("Error while adding route: %v", err)
+		return errors.Wrap(err, "Error while adding route")
 	}
 
 	return nil
@@ -163,7 +164,7 @@ func (nw *NetlinkWriter) removeKernel(pfx bnet.Prefix, paths []*route.Path) erro
 
 	err = netlink.RouteDel(route)
 	if err != nil {
-		return fmt.Errorf("Error while removing route: %v", err)
+		return errors.Wrap(err, "Error while removing route")
 	}
 
 	return nil
diff --git a/routingtable/adjRIBOut/adj_rib_out.go b/routingtable/adjRIBOut/adj_rib_out.go
index c9a0bb90090bd3870a646684959c310e513d0d62..de568f7297369e5c4f46a2bd3e2edd0dab392e69 100644
--- a/routingtable/adjRIBOut/adj_rib_out.go
+++ b/routingtable/adjRIBOut/adj_rib_out.go
@@ -8,6 +8,7 @@ import (
 	"github.com/bio-routing/bio-rd/route"
 	"github.com/bio-routing/bio-rd/routingtable"
 	"github.com/bio-routing/bio-rd/routingtable/filter"
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 )
 
@@ -98,7 +99,7 @@ func (a *AdjRIBOut) AddPath(pfx bnet.Prefix, p *route.Path) error {
 	if a.addPathTX {
 		pathID, err := a.pathIDManager.addPath(p)
 		if err != nil {
-			return fmt.Errorf("Unable to get path ID: %v", err)
+			return errors.Wrap(err, "Unable to get path ID")
 		}
 
 		p.BGPPath.PathIdentifier = pathID
diff --git a/util/decode/decode.go b/util/decode/decode.go
index e6342f81a60e2806d410376f4d257e1077fb8afe..44489fbc5f753db4ea42976ad5df1795ed70288d 100644
--- a/util/decode/decode.go
+++ b/util/decode/decode.go
@@ -3,7 +3,8 @@ package decode
 import (
 	"bytes"
 	"encoding/binary"
-	"fmt"
+
+	"github.com/pkg/errors"
 )
 
 // Decode reads fields from a buffer
@@ -12,7 +13,7 @@ func Decode(buf *bytes.Buffer, fields []interface{}) error {
 	for _, field := range fields {
 		err = binary.Read(buf, binary.BigEndian, field)
 		if err != nil {
-			return fmt.Errorf("Unable to read from buffer: %v", err)
+			return errors.Wrap(err, "Unable to read from buffer")
 		}
 	}
 	return nil
diff --git a/util/decoder/decoder.go b/util/decoder/decoder.go
index 709e39352a32471d241112a0c205a8a70b4e34bb..7891f8c2642be02c94e34bd8307eec0b848a1574 100644
--- a/util/decoder/decoder.go
+++ b/util/decoder/decoder.go
@@ -3,7 +3,8 @@ package decoder
 import (
 	"bytes"
 	"encoding/binary"
-	"fmt"
+
+	"github.com/pkg/errors"
 )
 
 // Decode decodes network packets
@@ -12,7 +13,7 @@ func Decode(buf *bytes.Buffer, fields []interface{}) error {
 	for _, field := range fields {
 		err = binary.Read(buf, binary.BigEndian, field)
 		if err != nil {
-			return fmt.Errorf("Unable to read from buffer: %v", err)
+			return errors.Wrap(err, "Unable to read from buffer")
 		}
 	}
 	return nil