diff --git a/services/backup/Cargo.lock b/services/backup/Cargo.lock
--- a/services/backup/Cargo.lock
+++ b/services/backup/Cargo.lock
@@ -756,6 +756,7 @@
  "chrono",
  "clap",
  "comm-services-lib",
+ "derive_more",
  "once_cell",
  "rand",
  "reqwest",
diff --git a/services/backup/Cargo.toml b/services/backup/Cargo.toml
--- a/services/backup/Cargo.toml
+++ b/services/backup/Cargo.toml
@@ -14,7 +14,10 @@
 aws-types = "0.55"
 chrono = "0.4"
 clap = { version = "4.0", features = ["derive", "env"] }
-comm-services-lib = { path = "../comm-services-lib", features = ["http", "blob-client"] }
+comm-services-lib = { path = "../comm-services-lib", features = [
+  "http",
+  "blob-client",
+] }
 once_cell = "1.17"
 rand = "0.8.5"
 tokio = { version = "1.24", features = ["rt-multi-thread", "macros"] }
@@ -26,6 +29,7 @@
 actix-web = "4.3"
 tracing-actix-web = "0.7.3"
 reqwest = "0.11.18"
+derive_more = "0.99"
 
 [build-dependencies]
 tonic-build = "0.8"
diff --git a/services/backup/src/error.rs b/services/backup/src/error.rs
new file mode 100644
--- /dev/null
+++ b/services/backup/src/error.rs
@@ -0,0 +1,64 @@
+use actix_web::{
+  error::{
+    ErrorBadRequest, ErrorConflict, ErrorInternalServerError,
+    ErrorServiceUnavailable, HttpError,
+  },
+  HttpResponse, ResponseError,
+};
+use comm_services_lib::blob::client::BlobServiceError;
+use reqwest::StatusCode;
+use tracing::{error, trace, warn};
+
+#[derive(
+  Debug, derive_more::Display, derive_more::From, derive_more::Error,
+)]
+pub enum BackupError {
+  BlobError(BlobServiceError),
+}
+
+impl From<&BackupError> for actix_web::Error {
+  fn from(value: &BackupError) -> Self {
+    trace!("Handling backup service error: {value}");
+    match value {
+      BackupError::BlobError(
+        err @ (BlobServiceError::ClientError(_)
+        | BlobServiceError::UnexpectedHttpStatus(_)
+        | BlobServiceError::ServerError
+        | BlobServiceError::UnexpectedError),
+      ) => {
+        warn!("Transient blob error occurred: {err}");
+        ErrorServiceUnavailable("please retry")
+      }
+      BackupError::BlobError(BlobServiceError::AlreadyExists) => {
+        ErrorConflict("blob already exists")
+      }
+      BackupError::BlobError(BlobServiceError::InvalidArguments) => {
+        ErrorBadRequest("bad request")
+      }
+      BackupError::BlobError(
+        err @ (BlobServiceError::URLError(_) | BlobServiceError::NotFound),
+      ) => {
+        error!("Unexpected blob error: {err}");
+        ErrorInternalServerError("server error")
+      }
+    }
+  }
+}
+
+impl From<BackupError> for HttpError {
+  fn from(value: BackupError) -> Self {
+    value.into()
+  }
+}
+
+impl ResponseError for BackupError {
+  fn error_response(&self) -> HttpResponse {
+    actix_web::Error::from(self).error_response()
+  }
+
+  fn status_code(&self) -> StatusCode {
+    actix_web::Error::from(self)
+      .as_response_error()
+      .status_code()
+  }
+}
diff --git a/services/backup/src/main.rs b/services/backup/src/main.rs
--- a/services/backup/src/main.rs
+++ b/services/backup/src/main.rs
@@ -6,6 +6,7 @@
 pub mod config;
 pub mod constants;
 pub mod database;
+pub mod error;
 pub mod http;
 pub mod utils;