diff --git a/.golangci.yml b/.golangci.yml
index 37bb309..1799277 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -70,7 +70,7 @@ run:
   # Define the Go version limit.
   # Mainly related to generics support in go1.18.
   # Default: use Go version from the go.mod file, fallback on the env var `GOVERSION`, fallback on 1.17
-  go: '1.17'
+  go: '1.20'
 
 
 # output configuration options
@@ -457,7 +457,7 @@ linters-settings:
   govet:
     # Report about shadowed variables.
     # Default: false
-    check-shadowing: false
+    shadow: true
 
     # Settings per analyzer.
     settings:
@@ -625,6 +625,7 @@ linters:
     - bodyclose
     - containedctx
     - contextcheck
+    - copyloopvar
     - cyclop
     # - decorder
     # - depguard
@@ -637,7 +638,6 @@ linters:
     # - errorlint
     # - exhaustive
     # - exhaustivestruct
-    - exportloopref
     # - forbidigo
     # - forcetypeassert
     # - funlen
@@ -650,7 +650,7 @@ linters:
     - gocyclo
     - godot
     # - godox
-    - goerr113
+    - err113
     - gofmt
     - gofumpt
     # - goheader
@@ -697,7 +697,6 @@ linters:
     - unparam
     - unused
     # - varnamelen
-    - vetshadow
     # - wastedassign
     # - whitespace
     # - wrapcheck
@@ -729,7 +728,7 @@ issues:
         - dupl
         - gocognit
         - gocyclo
-        - goerr113
+        - err113
         - gosec
 
     - path: _test\.go
diff --git a/README.md b/README.md
index 0a46d4e..6b797c2 100644
--- a/README.md
+++ b/README.md
@@ -41,35 +41,44 @@ This project is an adaptation for Google's Go / Golang programming language.
 
 ## Table of content
 
-- [Simple VCR example](#simple-vcr-example)
-- [Install](#install)
-- [Glossary of Terms](#glossary-of-terms)
-- [Concepts](#concepts)
-  - [VCRSettings](#vcrsettings)
-- [Match a request to a cassette track](#match-a-request-to-a-cassette-track)
-- [Track mutators](#track-mutators)
-- [Cassette encryption](#cassette-encryption)
-- [Cookbook](#cookbook)
-  - [Run the examples](#run-the-examples)
-  - [Recipe: VCR with custom `http.Client`](#recipe-vcr-with-custom-httpclient)
-  - [Recipe: Remove Response TLS](#recipe-remove-response-tls)
-  - [Recipe: Change the playback mode of the VCR](#recipe-change-the-playback-mode-of-the-vcr)
-  - [Recipe: VCR with encrypted cassette](#recipe-vcr-with-encrypted-cassette)
-  - [Recipe: VCR with encrypted cassette - custom nonce generator](#recipe-vcr-with-encrypted-cassette---custom-nonce-generator)
-  - [Recipe: Cassette decryption](#recipe-cassette-decryption)
-  - [Recipe: Changing cassette encryption](#recipe-changing-cassette-encryption)
-  - [Recipe: VCR with cassette storage on AWS S3](#recipe-vcr-with-cassette-storage-on-aws-s3)
-  - [Recipe: VCR with a custom RequestMatcher](#recipe-vcr-with-a-custom-requestmatcher)
-  - [Recipe: VCR with a replaying Track Mutator](#recipe-vcr-with-a-replaying-track-mutator)
-  - [Recipe: VCR with a recording Track Mutator](#recipe-vcr-with-a-recording-track-mutator)
-  - [More](#more)
-- [Stats](#stats)
-- [Run the tests](#run-the-tests)
-- [Bugs](#bugs)
-- [Improvements](#improvements)
-- [Limitations](#limitations)
-- [Contribute](#contribute)
-- [Community Support Appeal](#community-support-appeal)
+- [govcr](#govcr)
+  - [Table of content](#table-of-content)
+  - [Simple VCR example](#simple-vcr-example)
+  - [Install](#install)
+  - [Glossary of Terms](#glossary-of-terms)
+  - [Concepts](#concepts)
+    - [VCRSettings](#vcrsettings)
+  - [Match a request to a cassette track](#match-a-request-to-a-cassette-track)
+  - [Track mutators](#track-mutators)
+  - [Cassette encryption](#cassette-encryption)
+  - [Cookbook](#cookbook)
+    - [Run the examples](#run-the-examples)
+    - [Recipe: VCR with custom `http.Client`](#recipe-vcr-with-custom-httpclient)
+    - [Recipe: Remove Response TLS](#recipe-remove-response-tls)
+    - [Recipe: Change the playback mode of the VCR](#recipe-change-the-playback-mode-of-the-vcr)
+      - [Normal HTTP mode](#normal-http-mode)
+      - [Live only HTTP mode](#live-only-http-mode)
+      - [Read only cassette mode](#read-only-cassette-mode)
+      - [Offline HTTP mode](#offline-http-mode)
+    - [Recipe: VCR with encrypted cassette](#recipe-vcr-with-encrypted-cassette)
+    - [Recipe: VCR with encrypted cassette - custom nonce generator](#recipe-vcr-with-encrypted-cassette---custom-nonce-generator)
+    - [Recipe: Cassette decryption](#recipe-cassette-decryption)
+    - [Recipe: Changing cassette encryption](#recipe-changing-cassette-encryption)
+    - [Recipe: VCR with cassette storage on AWS S3](#recipe-vcr-with-cassette-storage-on-aws-s3)
+    - [Recipe: VCR with a custom RequestMatcher](#recipe-vcr-with-a-custom-requestmatcher)
+    - [Recipe: VCR with a replaying Track Mutator](#recipe-vcr-with-a-replaying-track-mutator)
+    - [Recipe: VCR with a recording Track Mutator](#recipe-vcr-with-a-recording-track-mutator)
+    - [More](#more)
+  - [Stats](#stats)
+  - [Run the tests](#run-the-tests)
+  - [Bugs](#bugs)
+  - [Improvements](#improvements)
+  - [Limitations](#limitations)
+    - [Go empty interfaces (`interface{}` / `any`)](#go-empty-interfaces-interface--any)
+    - [Support for multiple values in HTTP headers](#support-for-multiple-values-in-http-headers)
+    - [HTTP transport errors](#http-transport-errors)
+  - [Contribute](#contribute)
+  - [Community Support Appeal](#community-support-appeal)
 
 ## Simple VCR example
 
@@ -626,7 +635,7 @@ Objects cannot be created by name at runtime in Go. Rather than re-create the or
 
 In practice, the implications for you depend on how much you care about the error type. If all you need to know is that an error occurred, you won't mind this limitation.
 
-Mitigation: Support for common errors (network down) has been implemented. Support for more error types can be implemented, if there is appetite for it.
+Mitigation: Support for common errors (network down, dns failure, timeout) has been implemented. Support for more error types can be implemented, if there is appetite for it.
 
 [(toc)](#table-of-content)
 
diff --git a/cassette/cassette.go b/cassette/cassette.go
index 8dedc26..8c54ebb 100644
--- a/cassette/cassette.go
+++ b/cassette/cassette.go
@@ -23,7 +23,7 @@ import (
 )
 
 // Cassette contains a set of tracks.
-// nolint: govet
+// nolint:govet
 type Cassette struct {
 	Tracks []track.Track
 
@@ -134,7 +134,7 @@ func (k7 *Cassette) NumberOfTracks() int32 {
 	k7.trackSliceMutex.RLock()
 	defer k7.trackSliceMutex.RUnlock()
 
-	return int32(len(k7.Tracks))
+	return int32(len(k7.Tracks)) //nolint:gosec // int32 can more than sufficiently hold the number of tracks on a cassette.
 }
 
 // ReplayTrack returns the specified track number, as recorded on cassette.
@@ -257,7 +257,7 @@ func (k7 *Cassette) EncryptionFilter(data []byte) ([]byte, error) {
 	header = append(header, byte(nonceLen))
 	header = append(header, nonce...)
 
-	// nolint: gocritic
+	// nolint:gocritic
 	eData := append(header, ciphertext...)
 
 	return eData, nil
diff --git a/cassette/track/http.go b/cassette/track/http.go
index b14704a..2d3b90c 100644
--- a/cassette/track/http.go
+++ b/cassette/track/http.go
@@ -19,7 +19,7 @@ import (
 // with a RequestMatcher (albeit perfectly possible).
 // These fields also help when converting Response to http.Response to
 // populate http.Response.Request.
-// nolint: govet
+// nolint:govet
 type Request struct {
 	Method           string
 	URL              *url.URL
@@ -172,7 +172,7 @@ func ToRequest(httpRequest *http.Request) *Request {
 }
 
 // Response is a track HTTP Response.
-// nolint: govet
+// nolint:govet
 type Response struct {
 	Status     string
 	StatusCode int
@@ -270,13 +270,13 @@ func cloneTLS(tlsCS *tls.ConnectionState) *tls.ConnectionState {
 		DidResume:                   tlsCS.DidResume,
 		CipherSuite:                 tlsCS.CipherSuite,
 		NegotiatedProtocol:          tlsCS.NegotiatedProtocol,
-		NegotiatedProtocolIsMutual:  tlsCS.NegotiatedProtocolIsMutual, //nolint: staticcheck
+		NegotiatedProtocolIsMutual:  tlsCS.NegotiatedProtocolIsMutual, //nolint:staticcheck
 		ServerName:                  tlsCS.ServerName,
 		PeerCertificates:            peerCertificatesClone,
 		VerifiedChains:              verifiedChainsClone,
 		SignedCertificateTimestamps: signedCertificateTimestampsClone,
 		OCSPResponse:                []byte(string(tlsCS.OCSPResponse)),
-		TLSUnique:                   []byte(string(tlsCS.TLSUnique)), //nolint: staticcheck
+		TLSUnique:                   []byte(string(tlsCS.TLSUnique)), //nolint:staticcheck
 	}
 }
 
diff --git a/cassette/track/track.go b/cassette/track/track.go
index 2e7c4ba..38b59e9 100644
--- a/cassette/track/track.go
+++ b/cassette/track/track.go
@@ -6,6 +6,7 @@ import (
 	"io"
 	"net"
 	"net/http"
+	"os"
 
 	"github.com/pkg/errors"
 
@@ -73,7 +74,8 @@ func (trk *Track) ToErr() error {
 		errMsg = *trk.ErrMsg
 	}
 
-	if errType == "*net.OpError" {
+	switch errType {
+	case "*net.OpError":
 		return &net.OpError{
 			Op:     "govcr",
 			Net:    "govcr",
@@ -81,6 +83,23 @@ func (trk *Track) ToErr() error {
 			Addr:   nil,
 			Err:    errors.WithStack(trkerr.NewErrTransportFailure(errType, errMsg)),
 		}
+
+	case "*os.SyscallError":
+		return &os.SyscallError{
+			Syscall: errMsg,
+			Err:     errors.WithStack(trkerr.NewErrTransportFailure(errType, errMsg)),
+		}
+
+	case "*net.DNSError":
+		return &net.DNSError{
+			UnwrapErr:   errors.WithStack(trkerr.NewErrTransportFailure(errType, errMsg)),
+			Err:         errMsg,
+			Name:        "govcr",
+			Server:      "govcr",
+			IsTimeout:   false,
+			IsTemporary: false,
+			IsNotFound:  false,
+		}
 	}
 
 	return errors.WithStack(trkerr.NewErrTransportFailure(errType, errMsg))
@@ -117,7 +136,7 @@ func (trk *Track) toHTTPRequest() *http.Request {
 }
 
 // ToHTTPResponse converts the track Response to an http.Response.
-// nolint: gocritic
+// nolint:gocritic
 func (trk Track) ToHTTPResponse() *http.Response {
 	if trk.Response == nil {
 		return nil
diff --git a/concurrency_test.go b/concurrency_test.go
index b965167..60160d9 100644
--- a/concurrency_test.go
+++ b/concurrency_test.go
@@ -97,7 +97,7 @@ func TestConcurrencySafety(t *testing.T) {
 						// check outcome of the request
 						expectedBody := generateBinaryBody(i1)
 						if err := validateResponseForTestPlaybackOrder(resp, expectedBody); err != nil {
-							t.Fatalf(err.Error())
+							t.Fatal(err.Error())
 						}
 					}()
 				})
diff --git a/controlpanel.go b/controlpanel.go
index 768f990..7f7d683 100644
--- a/controlpanel.go
+++ b/controlpanel.go
@@ -100,5 +100,5 @@ func (controlPanel *ControlPanel) NumberOfTracks() int32 {
 }
 
 func (controlPanel *ControlPanel) vcrTransport() *vcrTransport {
-	return controlPanel.client.Transport.(*vcrTransport)
+	return controlPanel.client.Transport.(*vcrTransport) //nolint:errcheck // either way, this would require a panic.
 }
diff --git a/encryption/.study/rsa.go b/encryption/.study/rsa.go
index dcc38ec..df14552 100644
--- a/encryption/.study/rsa.go
+++ b/encryption/.study/rsa.go
@@ -14,7 +14,7 @@ import (
 	cryptoerr "github.com/seborama/govcr/v15/encryption/errors"
 )
 
-// nolint: deadcode
+// nolint:deadcode
 // TODO: offer ability to supply the key via an environment variable in base64 format.
 func readSSHRSAPrivateKeyFile(privKeyFile, passphrase string) (rsaPrivKey *rsa.PrivateKey, sshSigner ssh.Signer, rsaPubKey *rsa.PublicKey, err error) {
 	keyData, err := os.ReadFile(privKeyFile)
@@ -61,7 +61,7 @@ func readSSHRSAPrivateKeyFile(privKeyFile, passphrase string) (rsaPrivKey *rsa.P
 	return rsaPrivKey, sshSigner, rsaPubKey, nil
 }
 
-// nolint: deadcode
+// nolint:deadcode
 // TODO: offer ability to supply the key via an environment variable in base64 format.
 func readSSHRSAPublicKeyFile(pubKeyFile string) (*rsa.PublicKey, error) {
 	keyData, err := os.ReadFile(pubKeyFile)
diff --git a/govcr_test.go b/govcr_test.go
index 8b90445..67fd3dc 100644
--- a/govcr_test.go
+++ b/govcr_test.go
@@ -294,7 +294,7 @@ func (ts *GoVCRTestSuite) TestVCR_OfflineMode() {
 	// we've run out of tracks on the cassette and we're in offline mode so we expect a transport error
 	req, err := http.NewRequest(http.MethodGet, ts.testServer.URL, nil)
 	ts.Require().NoError(err)
-	resp, err := vcr.HTTPClient().Do(req) //nolint: bodyclose
+	resp, err := vcr.HTTPClient().Do(req) //nolint:bodyclose
 	ts.Require().Error(err)
 	ts.Assert().Contains(err.Error(), "no track matched on cassette and offline mode is active")
 	ts.Assert().Nil(resp)
@@ -338,7 +338,7 @@ func (ts *GoVCRTestSuite) TestRoundTrip_ReplaysError() {
 			// execute HTTP call and record on cassette
 			vcr := ts.newVCR(cassetteName, actionDeleteCassette)
 
-			resp, err := vcr.HTTPClient().Get(tc.reqURL) //nolint: bodyclose
+			resp, err := vcr.HTTPClient().Get(tc.reqURL) //nolint:bodyclose
 			ts.Require().Error(err)
 			ts.EqualError(err, tc.wantErr)
 			ts.Require().Nil(resp)
@@ -356,7 +356,7 @@ func (ts *GoVCRTestSuite) TestRoundTrip_ReplaysError() {
 			vcr = ts.newVCR(cassetteName, actionKeepCassette)
 			ts.EqualValues(1, vcr.NumberOfTracks())
 
-			resp, err = vcr.HTTPClient().Get(tc.reqURL) //nolint: bodyclose
+			resp, err = vcr.HTTPClient().Get(tc.reqURL) //nolint:bodyclose
 			ts.Require().Error(err)
 			ts.EqualError(err, tc.wantVCRErr)
 			ts.Require().Nil(resp)
diff --git a/govcr_wb_test.go b/govcr_wb_test.go
index d6f6c21..76a1c41 100644
--- a/govcr_wb_test.go
+++ b/govcr_wb_test.go
@@ -140,7 +140,7 @@ func (ts *GoVCRWBTestSuite) TestRoundTrip_RequestMatcherDoesNotMutateState() {
 	req, err = http.NewRequest(http.MethodGet, ts.testServer.URL, nil)
 	ts.Require().NoError(err)
 
-	resp2, err := vcr.HTTPClient().Do(req) //nolint: bodyclose
+	resp2, err := vcr.HTTPClient().Do(req) //nolint:bodyclose
 	ts.Require().NoError(err)
 	defer func() { _ = resp.Body.Close() }()
 
diff --git a/matchers.go b/matchers.go
index d509cbb..e2e4c13 100644
--- a/matchers.go
+++ b/matchers.go
@@ -62,7 +62,7 @@ func DefaultMethodMatcher(httpRequest, trackRequest *track.Request) bool {
 }
 
 // DefaultURLMatcher is the default implementation of URLMatcher.
-// nolint: gocyclo,gocognit
+// nolint:gocyclo,gocognit
 func DefaultURLMatcher(httpRequest, trackRequest *track.Request) bool {
 	httpURL := httpRequest.URL
 	if httpURL == nil {
@@ -95,7 +95,7 @@ func DefaultTrailerMatcher(httpRequest, trackRequest *track.Request) bool {
 	return areHTTPHeadersEqual(httpRequest.Trailer, trackRequest.Trailer)
 }
 
-// nolint: gocyclo,gocognit
+// nolint:gocyclo,gocognit
 func areHTTPHeadersEqual(httpHeaders1, httpHeaders2 http.Header) bool {
 	if len(httpHeaders1) != len(httpHeaders2) {
 		return false
diff --git a/vcrtransport.go b/vcrtransport.go
index d302525..f9075e2 100644
--- a/vcrtransport.go
+++ b/vcrtransport.go
@@ -43,7 +43,7 @@ func (t *vcrTransport) RoundTrip(httpRequest *http.Request) (*http.Response, err
 		httpResponse := trk.ToHTTPResponse()
 		httpError := trk.ToErr()
 
-		return httpResponse, httpError //nolint: wrapcheck
+		return httpResponse, httpError //nolint:wrapcheck
 	}
 
 	if t.pcb.httpMode == HTTPModeOffline {