diff --git a/Corona-Warn-App/config/detekt.yml b/Corona-Warn-App/config/detekt.yml
index 9cad3798d18540090f8b68a1d2ff5db08437dc99..16a273985e2f434472dd1d4104a14236a9b48df4 100644
--- a/Corona-Warn-App/config/detekt.yml
+++ b/Corona-Warn-App/config/detekt.yml
@@ -66,7 +66,7 @@ complexity:
     active: true
     threshold: 15
     ignoreSingleWhenExpression: false
-    ignoreSimpleWhenEntries: false
+    ignoreSimpleWhenEntries: true
     ignoreNestingFunctions: false
     nestingFunctions: [run, let, apply, with, also, use, forEach, isNotNull, ifNull]
   LabeledExpression:
@@ -514,7 +514,15 @@ style:
     maxJumpCount: 1
   MagicNumber:
     active: true
-    excludes: ['**/test/**', '**/androidTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt']
+    excludes: [
+      '**/test/**',
+      '**/androidTest/**',
+      '**/*.Test.kt',
+      '**/*.Spec.kt',
+      '**/*.Spek.kt',
+      '**/CwaWebException.kt',
+      '**/HttpErrorParser.kt'
+    ]
     ignoreNumbers: ['-1', '0', '1', '2']
     ignoreHashCodeFunction: true
     ignorePropertyDeclaration: false
@@ -523,7 +531,7 @@ style:
     ignoreCompanionObjectPropertyDeclaration: true
     ignoreAnnotation: false
     ignoreNamedArgument: true
-    ignoreEnums: false
+    ignoreEnums: true
     ignoreRanges: false
   MandatoryBracesIfStatements:
     active: false
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/SubmissionTanInvalidException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/SubmissionTanInvalidException.kt
deleted file mode 100644
index 55b2acb7cdec3cf93d9a5984555c4fa8ff330afe..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/SubmissionTanInvalidException.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/******************************************************************************
- * Corona-Warn-App                                                            *
- *                                                                            *
- * SAP SE and all other contributors /                                        *
- * copyright owners license this file to you under the Apache                 *
- * License, Version 2.0 (the "License"); you may not use this                 *
- * file except in compliance with the License.                                *
- * You may obtain a copy of the License at                                    *
- *                                                                            *
- * http://www.apache.org/licenses/LICENSE-2.0                                 *
- *                                                                            *
- * Unless required by applicable law or agreed to in writing,                 *
- * software distributed under the License is distributed on an                *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY                     *
- * KIND, either express or implied.  See the License for the                  *
- * specific language governing permissions and limitations                    *
- * under the License.                                                         *
- ******************************************************************************/
-
-package de.rki.coronawarnapp.exception
-
-/**
- * An Exception thrown when an error occurs inside the [de.rki.coronawarnapp.http.WebRequestBuilder]
- *
- * @param message an Exception thrown inside the WebRequestBuilder
- * @param cause the cause of the error
- */
-class SubmissionTanInvalidException(message: String, cause: Throwable) : Exception(message, cause)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/TestAlreadyPairedException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/TestAlreadyPairedException.kt
deleted file mode 100644
index b2af0b017dc78c66307862b0fb7486ab61ba77dc..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/TestAlreadyPairedException.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/******************************************************************************
- * Corona-Warn-App                                                            *
- *                                                                            *
- * SAP SE and all other contributors /                                        *
- * copyright owners license this file to you under the Apache                 *
- * License, Version 2.0 (the "License"); you may not use this                 *
- * file except in compliance with the License.                                *
- * You may obtain a copy of the License at                                    *
- *                                                                            *
- * http://www.apache.org/licenses/LICENSE-2.0                                 *
- *                                                                            *
- * Unless required by applicable law or agreed to in writing,                 *
- * software distributed under the License is distributed on an                *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY                     *
- * KIND, either express or implied.  See the License for the                  *
- * specific language governing permissions and limitations                    *
- * under the License.                                                         *
- ******************************************************************************/
-
-package de.rki.coronawarnapp.exception
-
-/**
- * An Exception thrown when an error occurs inside the [de.rki.coronawarnapp.http.WebRequestBuilder]
- *
- * @param message an Exception thrown inside the WebRequestBuilder
- * @param cause the cause of the error
- */
-class TestAlreadyPairedException(message: String, cause: Throwable) : Exception(message, cause)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/TestPairingInvalidException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/TestPairingInvalidException.kt
deleted file mode 100644
index 77619440763a0013c56848bdeb4267ea0bda7f26..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/TestPairingInvalidException.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/******************************************************************************
- * Corona-Warn-App                                                            *
- *                                                                            *
- * SAP SE and all other contributors /                                        *
- * copyright owners license this file to you under the Apache                 *
- * License, Version 2.0 (the "License"); you may not use this                 *
- * file except in compliance with the License.                                *
- * You may obtain a copy of the License at                                    *
- *                                                                            *
- * http://www.apache.org/licenses/LICENSE-2.0                                 *
- *                                                                            *
- * Unless required by applicable law or agreed to in writing,                 *
- * software distributed under the License is distributed on an                *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY                     *
- * KIND, either express or implied.  See the License for the                  *
- * specific language governing permissions and limitations                    *
- * under the License.                                                         *
- ******************************************************************************/
-
-package de.rki.coronawarnapp.exception
-
-/**
- * An Exception thrown when an error occurs inside the [de.rki.coronawarnapp.http.WebRequestBuilder]
- *
- * @param message an Exception thrown inside the WebRequestBuilder
- * @param cause the cause of the error
- */
-class TestPairingInvalidException(message: String, cause: Throwable) : Exception(message, cause)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/WebRequestException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/WebRequestException.kt
deleted file mode 100644
index bb9d4442e47d1b0ef8e4d48bcfdcf6aeb6ecfc9b..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/WebRequestException.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/******************************************************************************
- * Corona-Warn-App                                                            *
- *                                                                            *
- * SAP SE and all other contributors /                                        *
- * copyright owners license this file to you under the Apache                 *
- * License, Version 2.0 (the "License"); you may not use this                 *
- * file except in compliance with the License.                                *
- * You may obtain a copy of the License at                                    *
- *                                                                            *
- * http://www.apache.org/licenses/LICENSE-2.0                                 *
- *                                                                            *
- * Unless required by applicable law or agreed to in writing,                 *
- * software distributed under the License is distributed on an                *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY                     *
- * KIND, either express or implied.  See the License for the                  *
- * specific language governing permissions and limitations                    *
- * under the License.                                                         *
- ******************************************************************************/
-
-package de.rki.coronawarnapp.exception
-
-/**
- * An Exception thrown when an error occurs inside the [de.rki.coronawarnapp.http.WebRequestBuilder]
- *
- * @param message an Exception thrown inside the WebRequestBuilder
- * @param cause the cause of the error
- */
-class WebRequestException(message: String, cause: Throwable) : Exception(message, cause)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/http/CwaWebException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/http/CwaWebException.kt
new file mode 100644
index 0000000000000000000000000000000000000000..fd628417f20e0d14c81b062a764c1f492f216931
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/http/CwaWebException.kt
@@ -0,0 +1,44 @@
+package de.rki.coronawarnapp.exception.http
+
+import java.io.IOException
+
+open class CwaWebException(statusCode: Int) : IOException(
+    "error during web request, http status $statusCode"
+)
+
+open class CwaServerError(val statusCode: Int) : CwaWebException(statusCode) {
+    init {
+        if (statusCode !in 500..599)
+            throw IllegalArgumentException("a server error has to have code 5xx")
+    }
+}
+
+open class CwaClientError(val statusCode: Int) : CwaWebException(statusCode) {
+    init {
+        if (statusCode !in 400..499)
+            throw IllegalArgumentException("a client error has to have code 4xx")
+    }
+}
+
+open class CwaSuccessResponseWithCodeMismatchNotSupportedError(val statusCode: Int) : CwaWebException(statusCode)
+open class CwaInformationalNotSupportedError(val statusCode: Int) : CwaWebException(statusCode)
+open class CwaRedirectNotSupportedError(val statusCode: Int) : CwaWebException(statusCode)
+
+class BadRequestException : CwaClientError(400)
+class UnauthorizedException : CwaClientError(401)
+class ForbiddenException : CwaClientError(403)
+class NotFoundException : CwaClientError(404)
+class ConflictException : CwaClientError(409)
+class GoneException : CwaClientError(410)
+class UnsupportedMediaTypeException : CwaClientError(415)
+class TooManyRequestsException : CwaClientError(429)
+
+class InternalServerErrorException : CwaServerError(500)
+class NotImplementedException : CwaServerError(501)
+class BadGatewayException : CwaServerError(502)
+class ServiceUnavailableException : CwaServerError(503)
+class GatewayTimeoutException : CwaServerError(504)
+class HTTPVersionNotSupported : CwaServerError(505)
+class NetworkAuthenticationRequiredException : CwaServerError(511)
+class NetworkReadTimeoutException : CwaServerError(598)
+class NetworkConnectTimeoutException : CwaServerError(599)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/HttpErrorParser.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/HttpErrorParser.kt
new file mode 100644
index 0000000000000000000000000000000000000000..660017005372030a02692f38070756fe25c3dc99
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/HttpErrorParser.kt
@@ -0,0 +1,64 @@
+package de.rki.coronawarnapp.http
+
+import de.rki.coronawarnapp.exception.http.BadGatewayException
+import de.rki.coronawarnapp.exception.http.CwaWebException
+import de.rki.coronawarnapp.exception.http.BadRequestException
+import de.rki.coronawarnapp.exception.http.ConflictException
+import de.rki.coronawarnapp.exception.http.CwaClientError
+import de.rki.coronawarnapp.exception.http.CwaInformationalNotSupportedError
+import de.rki.coronawarnapp.exception.http.CwaRedirectNotSupportedError
+import de.rki.coronawarnapp.exception.http.CwaServerError
+import de.rki.coronawarnapp.exception.http.CwaSuccessResponseWithCodeMismatchNotSupportedError
+import de.rki.coronawarnapp.exception.http.ForbiddenException
+import de.rki.coronawarnapp.exception.http.GatewayTimeoutException
+import de.rki.coronawarnapp.exception.http.GoneException
+import de.rki.coronawarnapp.exception.http.HTTPVersionNotSupported
+import de.rki.coronawarnapp.exception.http.InternalServerErrorException
+import de.rki.coronawarnapp.exception.http.NetworkAuthenticationRequiredException
+import de.rki.coronawarnapp.exception.http.NetworkConnectTimeoutException
+import de.rki.coronawarnapp.exception.http.NetworkReadTimeoutException
+import de.rki.coronawarnapp.exception.http.NotFoundException
+import de.rki.coronawarnapp.exception.http.NotImplementedException
+import de.rki.coronawarnapp.exception.http.ServiceUnavailableException
+import de.rki.coronawarnapp.exception.http.TooManyRequestsException
+import de.rki.coronawarnapp.exception.http.UnauthorizedException
+import de.rki.coronawarnapp.exception.http.UnsupportedMediaTypeException
+import okhttp3.Interceptor
+import okhttp3.Response
+
+class HttpErrorParser : Interceptor {
+    override fun intercept(chain: Interceptor.Chain): Response {
+        val response = chain.proceed(chain.request())
+        return when (val code = response.code) {
+            200 -> response
+            201 -> response
+            202 -> response
+            204 -> response
+            400 -> throw BadRequestException()
+            401 -> throw UnauthorizedException()
+            403 -> throw ForbiddenException()
+            404 -> throw NotFoundException()
+            409 -> throw ConflictException()
+            410 -> throw GoneException()
+            415 -> throw UnsupportedMediaTypeException()
+            429 -> throw TooManyRequestsException()
+            500 -> throw InternalServerErrorException()
+            501 -> throw NotImplementedException()
+            502 -> throw BadGatewayException()
+            503 -> throw ServiceUnavailableException()
+            504 -> throw GatewayTimeoutException()
+            505 -> throw HTTPVersionNotSupported()
+            511 -> throw NetworkAuthenticationRequiredException()
+            598 -> throw NetworkReadTimeoutException()
+            599 -> throw NetworkConnectTimeoutException()
+            else -> {
+                if (code in 100..199) throw CwaInformationalNotSupportedError(code)
+                if (code in 200..299) throw CwaSuccessResponseWithCodeMismatchNotSupportedError(code)
+                if (code in 300..399) throw CwaRedirectNotSupportedError(code)
+                if (code in 400..499) throw CwaClientError(code)
+                if (code in 500..599) throw CwaServerError(code)
+                throw CwaWebException(code)
+            }
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/ServiceFactory.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/ServiceFactory.kt
index b17803daad10bc54513d4fb4ef98273d60dccdac..90c2fd6fcfcdccf1e1859481c1e7d7bb1e5d1a1b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/ServiceFactory.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/ServiceFactory.kt
@@ -39,7 +39,8 @@ class ServiceFactory {
             if (BuildConfig.DEBUG) it.setLevel(HttpLoggingInterceptor.Level.BODY)
         },
         OfflineCacheInterceptor(CoronaWarnApplication.getAppContext()),
-        RetryInterceptor()
+        RetryInterceptor(),
+        HttpErrorParser()
     )
 
     /**
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/diagnosiskey/DiagnosisKeyService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/diagnosiskey/DiagnosisKeyService.kt
index e30de86ea5638e506f54bbe7e1fa17af954907ae..fc4cc03daa3f1b55fb7581869329283a6973a5bf 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/diagnosiskey/DiagnosisKeyService.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/diagnosiskey/DiagnosisKeyService.kt
@@ -23,10 +23,7 @@ import KeyExportFormat
 import android.util.Log
 import de.rki.coronawarnapp.exception.DiagnosisKeyRetrievalException
 import de.rki.coronawarnapp.exception.DiagnosisKeySubmissionException
-import de.rki.coronawarnapp.exception.SubmissionTanInvalidException
 import de.rki.coronawarnapp.http.WebRequestBuilder
-import de.rki.coronawarnapp.service.diagnosiskey.DiagnosisKeyConstants.SERVER_ERROR_CODE_403
-import retrofit2.HttpException
 
 /**
  * The Diagnosis Key Service is used to interact with the Server to submit and retrieve keys through
@@ -50,21 +47,11 @@ object DiagnosisKeyService {
      * @param keysToReport - KeyList in the Server Format to submit to the Server
      */
     suspend fun asyncSubmitKeys(authCode: String, keysToReport: List<KeyExportFormat.TemporaryExposureKey>) {
-        try {
-            Log.d(TAG, "Diagnosis Keys will be submitted.")
-            WebRequestBuilder.asyncSubmitKeysToServer(
-                authCode,
-                false,
-                keysToReport
-            )
-        } catch (e: HttpException) {
-            if (e.code() == SERVER_ERROR_CODE_403) {
-                throw SubmissionTanInvalidException(
-                    "the test paring to the device is invalid",
-                    e
-                )
-            }
-            throw e
-        }
+        Log.d(TAG, "Diagnosis Keys will be submitted.")
+        WebRequestBuilder.asyncSubmitKeysToServer(
+            authCode,
+            false,
+            keysToReport
+        )
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt
index fc3f32667585ee228730635d6bd99d74b052528f..6cdd39fee0dc016c5cc81b382fc8a3da92d809f8 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt
@@ -2,38 +2,24 @@ package de.rki.coronawarnapp.service.submission
 
 import de.rki.coronawarnapp.exception.NoGUIDOrTANSetException
 import de.rki.coronawarnapp.exception.NoRegistrationTokenSetException
-import de.rki.coronawarnapp.exception.TestAlreadyPairedException
-import de.rki.coronawarnapp.exception.TestPairingInvalidException
 import de.rki.coronawarnapp.http.WebRequestBuilder
 import de.rki.coronawarnapp.service.submission.SubmissionConstants.QR_CODE_KEY_TYPE
-import de.rki.coronawarnapp.service.submission.SubmissionConstants.SERVER_ERROR_CODE_400
 import de.rki.coronawarnapp.service.submission.SubmissionConstants.TELE_TAN_KEY_TYPE
 import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.transaction.SubmitDiagnosisKeysTransaction
 import de.rki.coronawarnapp.util.formatter.TestResult
-import retrofit2.HttpException
 
 object SubmissionService {
     suspend fun asyncRegisterDevice() {
-        try {
-            val testGUID = LocalData.testGUID()
-            val testTAN = LocalData.teletan()
-
-            when {
-                testGUID != null -> asyncRegisterDeviceViaGUID(testGUID)
-                testTAN != null -> asyncRegisterDeviceViaTAN(testTAN)
-                else -> throw NoGUIDOrTANSetException()
-            }
-            LocalData.devicePairingSuccessfulTimestamp(System.currentTimeMillis())
-        } catch (err: HttpException) {
-            if (err.code() == SERVER_ERROR_CODE_400) {
-                throw TestAlreadyPairedException(
-                    "the test was already paired to a different device",
-                    err
-                )
-            }
-            throw err
+        val testGUID = LocalData.testGUID()
+        val testTAN = LocalData.teletan()
+
+        when {
+            testGUID != null -> asyncRegisterDeviceViaGUID(testGUID)
+            testTAN != null -> asyncRegisterDeviceViaTAN(testTAN)
+            else -> throw NoGUIDOrTANSetException()
         }
+        LocalData.devicePairingSuccessfulTimestamp(System.currentTimeMillis())
     }
 
     private suspend fun asyncRegisterDeviceViaGUID(guid: String) {
@@ -59,17 +45,7 @@ object SubmissionService {
     }
 
     suspend fun asyncRequestAuthCode(registrationToken: String): String {
-        try {
-            return WebRequestBuilder.asyncGetTan(registrationToken)
-        } catch (err: HttpException) {
-            if (err.code() == SERVER_ERROR_CODE_400) {
-                throw TestPairingInvalidException(
-                    "the test paring to the device is invalid",
-                    err
-                )
-            }
-            throw err
-        }
+        return WebRequestBuilder.asyncGetTan(registrationToken)
     }
 
     suspend fun asyncSubmitExposureKeys() {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionQRCodeScanFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionQRCodeScanFragment.kt
index 97d467a1fb5abd3191f3cd0911c41741d189b4fd..0b3a2ccef22e5f04abe422283661632a1612281e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionQRCodeScanFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionQRCodeScanFragment.kt
@@ -11,14 +11,16 @@ import com.journeyapps.barcodescanner.BarcodeResult
 import com.journeyapps.barcodescanner.DefaultDecoderFactory
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.FragmentSubmissionQrCodeScanBinding
-import de.rki.coronawarnapp.exception.TestAlreadyPairedException
+import de.rki.coronawarnapp.exception.http.BadRequestException
+import de.rki.coronawarnapp.exception.http.CwaClientError
+import de.rki.coronawarnapp.exception.http.CwaServerError
+import de.rki.coronawarnapp.exception.http.CwaWebException
 import de.rki.coronawarnapp.ui.BaseFragment
 import de.rki.coronawarnapp.ui.main.MainActivity
 import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel
 import de.rki.coronawarnapp.util.CameraPermissionHelper
 import de.rki.coronawarnapp.util.DialogHelper
 import de.rki.coronawarnapp.util.observeEvent
-import retrofit2.HttpException
 
 /**
  * A simple [BaseFragment] subclass.
@@ -57,9 +59,9 @@ class SubmissionQRCodeScanFragment : BaseFragment() {
         _binding = null
     }
 
-    private fun buildErrorDialog(exception: Exception): DialogHelper.DialogInstance {
+    private fun buildErrorDialog(exception: CwaWebException): DialogHelper.DialogInstance {
         return when (exception) {
-            is TestAlreadyPairedException -> DialogHelper.DialogInstance(
+            is BadRequestException -> DialogHelper.DialogInstance(
                 requireActivity(),
                 R.string.submission_error_dialog_web_test_paired_title,
                 R.string.submission_error_dialog_web_test_paired_body,
@@ -68,12 +70,24 @@ class SubmissionQRCodeScanFragment : BaseFragment() {
                 true,
                 ::navigateToDispatchScreen
             )
-            is HttpException -> DialogHelper.DialogInstance(
+            is CwaServerError -> DialogHelper.DialogInstance(
                 requireActivity(),
                 R.string.submission_error_dialog_web_generic_error_title,
                 getString(
                     R.string.submission_error_dialog_web_generic_network_error_body,
-                    exception.code()
+                    exception.statusCode
+                ),
+                R.string.submission_error_dialog_web_generic_error_button_positive,
+                null,
+                true,
+                ::navigateToDispatchScreen
+            )
+            is CwaClientError -> DialogHelper.DialogInstance(
+                requireActivity(),
+                R.string.submission_error_dialog_web_generic_error_title,
+                getString(
+                    R.string.submission_error_dialog_web_generic_network_error_body,
+                    exception.statusCode
                 ),
                 R.string.submission_error_dialog_web_generic_error_button_positive,
                 null,
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionResultPositiveOtherWarningFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionResultPositiveOtherWarningFragment.kt
index 477722597f323742bbc75b7810a9839bb4228c79..028722347093ef522fb84bcc1ec8c8a92ce6ee27 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionResultPositiveOtherWarningFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionResultPositiveOtherWarningFragment.kt
@@ -8,15 +8,16 @@ import androidx.fragment.app.activityViewModels
 import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.FragmentSubmissionPositiveOtherWarningBinding
-import de.rki.coronawarnapp.exception.SubmissionTanInvalidException
-import de.rki.coronawarnapp.exception.TestPairingInvalidException
+import de.rki.coronawarnapp.exception.http.BadRequestException
+import de.rki.coronawarnapp.exception.http.CwaClientError
+import de.rki.coronawarnapp.exception.http.CwaServerError
+import de.rki.coronawarnapp.exception.http.ForbiddenException
 import de.rki.coronawarnapp.nearby.InternalExposureNotificationPermissionHelper
 import de.rki.coronawarnapp.ui.BaseFragment
 import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel
 import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel
 import de.rki.coronawarnapp.util.DialogHelper
 import de.rki.coronawarnapp.util.observeEvent
-import retrofit2.HttpException
 
 class SubmissionResultPositiveOtherWarningFragment : BaseFragment(),
     InternalExposureNotificationPermissionHelper.Callback {
@@ -71,7 +72,7 @@ class SubmissionResultPositiveOtherWarningFragment : BaseFragment(),
 
     private fun buildErrorDialog(exception: Exception): DialogHelper.DialogInstance {
         return when (exception) {
-            is TestPairingInvalidException -> DialogHelper.DialogInstance(
+            is BadRequestException -> DialogHelper.DialogInstance(
                 requireActivity(),
                 R.string.submission_error_dialog_web_paring_invalid_title,
                 R.string.submission_error_dialog_web_paring_invalid_body,
@@ -80,7 +81,7 @@ class SubmissionResultPositiveOtherWarningFragment : BaseFragment(),
                 true,
                 ::navigateToSubmissionResultFragment
             )
-            is SubmissionTanInvalidException -> DialogHelper.DialogInstance(
+            is ForbiddenException -> DialogHelper.DialogInstance(
                 requireActivity(),
                 R.string.submission_error_dialog_web_tan_invalid_title,
                 R.string.submission_error_dialog_web_tan_invalid_body,
@@ -89,12 +90,24 @@ class SubmissionResultPositiveOtherWarningFragment : BaseFragment(),
                 true,
                 ::navigateToSubmissionResultFragment
             )
-            is HttpException -> DialogHelper.DialogInstance(
+            is CwaServerError -> DialogHelper.DialogInstance(
                 requireActivity(),
                 R.string.submission_error_dialog_web_generic_error_title,
                 getString(
                     R.string.submission_error_dialog_web_generic_network_error_body,
-                    exception.code()
+                    exception.statusCode
+                ),
+                R.string.submission_error_dialog_web_generic_error_button_positive,
+                null,
+                true,
+                ::navigateToSubmissionResultFragment
+            )
+            is CwaClientError -> DialogHelper.DialogInstance(
+                requireActivity(),
+                R.string.submission_error_dialog_web_generic_error_title,
+                getString(
+                    R.string.submission_error_dialog_web_generic_network_error_body,
+                    exception.statusCode
                 ),
                 R.string.submission_error_dialog_web_generic_error_button_positive,
                 null,
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanFragment.kt
index 56b4c46080f5b3e26f65d54d6fd303516960cde8..62877109447b67dfc21794e91302ba14101bab7c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanFragment.kt
@@ -7,12 +7,14 @@ import android.view.ViewGroup
 import androidx.fragment.app.activityViewModels
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.FragmentSubmissionTanBinding
-import de.rki.coronawarnapp.exception.TestAlreadyPairedException
+import de.rki.coronawarnapp.exception.http.BadRequestException
+import de.rki.coronawarnapp.exception.http.CwaClientError
+import de.rki.coronawarnapp.exception.http.CwaServerError
+import de.rki.coronawarnapp.exception.http.CwaWebException
 import de.rki.coronawarnapp.ui.BaseFragment
 import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel
 import de.rki.coronawarnapp.util.DialogHelper
 import de.rki.coronawarnapp.util.observeEvent
-import retrofit2.HttpException
 
 /**
  * Fragment for TAN entry
@@ -41,9 +43,9 @@ class SubmissionTanFragment : BaseFragment() {
         _binding = null
     }
 
-    private fun buildErrorDialog(exception: Exception): DialogHelper.DialogInstance {
+    private fun buildErrorDialog(exception: CwaWebException): DialogHelper.DialogInstance {
         return when (exception) {
-            is TestAlreadyPairedException -> DialogHelper.DialogInstance(
+            is BadRequestException -> DialogHelper.DialogInstance(
                 requireActivity(),
                 R.string.submission_error_dialog_web_test_paired_title,
                 R.string.submission_error_dialog_web_test_paired_body,
@@ -52,12 +54,24 @@ class SubmissionTanFragment : BaseFragment() {
                 true,
                 ::navigateToDispatchScreen
             )
-            is HttpException -> DialogHelper.DialogInstance(
+            is CwaServerError -> DialogHelper.DialogInstance(
                 requireActivity(),
                 R.string.submission_error_dialog_web_generic_error_title,
                 getString(
                     R.string.submission_error_dialog_web_generic_network_error_body,
-                    exception.code()
+                    exception.statusCode
+                ),
+                R.string.submission_error_dialog_web_generic_error_button_positive,
+                null,
+                true,
+                ::navigateToDispatchScreen
+            )
+            is CwaClientError -> DialogHelper.DialogInstance(
+                requireActivity(),
+                R.string.submission_error_dialog_web_generic_error_title,
+                getString(
+                    R.string.submission_error_dialog_web_generic_network_error_body,
+                    exception.statusCode
                 ),
                 R.string.submission_error_dialog_web_generic_error_button_positive,
                 null,
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultFragment.kt
index c0b07dfed349f80f0f7114d0854163cb4174504c..3037b5b61e06f05badae73a6dccf4fdb656e2de0 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultFragment.kt
@@ -7,12 +7,14 @@ import android.view.ViewGroup
 import androidx.fragment.app.activityViewModels
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.FragmentSubmissionTestResultBinding
+import de.rki.coronawarnapp.exception.http.CwaClientError
+import de.rki.coronawarnapp.exception.http.CwaServerError
+import de.rki.coronawarnapp.exception.http.CwaWebException
 import de.rki.coronawarnapp.ui.BaseFragment
 import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel
 import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel
 import de.rki.coronawarnapp.util.DialogHelper
 import de.rki.coronawarnapp.util.observeEvent
-import retrofit2.HttpException
 
 /**
  * A simple [BaseFragment] subclass.
@@ -44,14 +46,26 @@ class SubmissionTestResultFragment : BaseFragment() {
     private fun navigateToMainScreen() =
         doNavigate(SubmissionTestResultFragmentDirections.actionSubmissionResultFragmentToMainFragment())
 
-    private fun buildErrorDialog(exception: Exception): DialogHelper.DialogInstance {
+    private fun buildErrorDialog(exception: CwaWebException): DialogHelper.DialogInstance {
         return when (exception) {
-            is HttpException -> DialogHelper.DialogInstance(
+            is CwaServerError -> DialogHelper.DialogInstance(
                 requireActivity(),
                 R.string.submission_error_dialog_web_generic_error_title,
                 getString(
                     R.string.submission_error_dialog_web_generic_network_error_body,
-                    exception.code()
+                    exception.statusCode
+                ),
+                R.string.submission_error_dialog_web_generic_error_button_positive,
+                null,
+                true,
+                ::navigateToMainScreen
+            )
+            is CwaClientError -> DialogHelper.DialogInstance(
+                requireActivity(),
+                R.string.submission_error_dialog_web_generic_error_title,
+                getString(
+                    R.string.submission_error_dialog_web_generic_network_error_body,
+                    exception.statusCode
                 ),
                 R.string.submission_error_dialog_web_generic_error_button_positive,
                 null,
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt
index 39431e54f092dde47557f367bf94e214925bad4b..60ab8b5cdc406b23fdd9b1530f2b3e074fc196e0 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt
@@ -4,6 +4,9 @@ import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewModelScope
+import de.rki.coronawarnapp.exception.ExceptionCategory
+import de.rki.coronawarnapp.exception.http.CwaWebException
+import de.rki.coronawarnapp.exception.report
 import de.rki.coronawarnapp.service.submission.SubmissionService
 import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.storage.SubmissionRepository
@@ -18,24 +21,24 @@ class SubmissionViewModel : ViewModel() {
     private val _scanStatus = MutableLiveData(Event(ScanStatus.STARTED))
 
     private val _registrationState = MutableLiveData(Event(ApiRequestState.IDLE))
-    private val _registrationError = MutableLiveData<Event<Exception>>(null)
+    private val _registrationError = MutableLiveData<Event<CwaWebException>>(null)
 
     private val _uiStateState = MutableLiveData(ApiRequestState.IDLE)
-    private val _uiStateError = MutableLiveData<Event<Exception>>(null)
+    private val _uiStateError = MutableLiveData<Event<CwaWebException>>(null)
 
     private val _submissionState = MutableLiveData(Event(ApiRequestState.IDLE))
-    private val _submissionError = MutableLiveData<Event<Exception>>(null)
+    private val _submissionError = MutableLiveData<Event<CwaWebException>>(null)
 
     val scanStatus: LiveData<Event<ScanStatus>> = _scanStatus
 
     val registrationState: LiveData<Event<ApiRequestState>> = _registrationState
-    val registrationError: LiveData<Event<Exception>> = _registrationError
+    val registrationError: LiveData<Event<CwaWebException>> = _registrationError
 
     val uiStateState: LiveData<ApiRequestState> = _uiStateState
-    val uiStateError: LiveData<Event<Exception>> = _uiStateError
+    val uiStateError: LiveData<Event<CwaWebException>> = _uiStateError
 
     val submissionState: LiveData<Event<ApiRequestState>> = _submissionState
-    val submissionError: LiveData<Event<Exception>> = _submissionError
+    val submissionError: LiveData<Event<CwaWebException>> = _submissionError
 
     val deviceRegistered get() = LocalData.registrationToken() != null
 
@@ -89,16 +92,18 @@ class SubmissionViewModel : ViewModel() {
     private fun executeRequestWithState(
         apiRequest: suspend () -> Unit,
         state: MutableLiveData<ApiRequestState>,
-        exceptionLiveData: MutableLiveData<Event<Exception>>? = null
+        exceptionLiveData: MutableLiveData<Event<CwaWebException>>? = null
     ) {
         state.value = ApiRequestState.STARTED
         viewModelScope.launch {
             try {
                 apiRequest()
                 state.value = ApiRequestState.SUCCESS
-            } catch (err: Exception) {
+            } catch (err: CwaWebException) {
                 exceptionLiveData?.value = Event(err)
                 state.value = ApiRequestState.FAILED
+            } catch (err: Exception) {
+                err.report(ExceptionCategory.INTERNAL)
             }
         }
     }
@@ -106,16 +111,18 @@ class SubmissionViewModel : ViewModel() {
     private fun executeRequestWithStateForEvent(
         apiRequest: suspend () -> Unit,
         state: MutableLiveData<Event<ApiRequestState>>,
-        exceptionLiveData: MutableLiveData<Event<Exception>>? = null
+        exceptionLiveData: MutableLiveData<Event<CwaWebException>>? = null
     ) {
         state.value = Event(ApiRequestState.STARTED)
         viewModelScope.launch {
             try {
                 apiRequest()
                 state.value = Event(ApiRequestState.SUCCESS)
-            } catch (err: Exception) {
+            } catch (err: CwaWebException) {
                 exceptionLiveData?.value = Event(err)
                 state.value = Event(ApiRequestState.FAILED)
+            } catch (err: Exception) {
+                err.report(ExceptionCategory.INTERNAL)
             }
         }
     }