Repository: deislabs/ratify
Pull request #956 (2023-07-31 15:27:30)

refactor: refactor error handling
# Description

## What this PR does / why we need it:
1. Refactor most errors to a custom error struct.
2. Each error would have an error code for fast searching. 
3. For plugin errors, there would be componentType indicating the plugin type, and pluginName indicating the plugin name, e.g. verifier as componentType, and notation-verifier as pluginName.
4. Add OriginalError so that we can trace the root error.
5. Add Stack so that we can debug the stack trace.
6. Add a doc listing all errors. More work need to be done in the future to have more information on debugging each error.

Design doc: https://hackmd.io/@H7a8_rG4SuaKwzu4NLT-9Q/HJ6bNe2c2

The exported error codes could be checked on pkg.go.dev, just like this: https://pkg.go.dev/github.com/distribution/distribution@v2.8.2+incompatible/registry/api/errcode#pkg-variables

## Which issue(s) this PR fixes *(optional, using `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when the PR gets merged)*:
Fixes https://github.com/deislabs/ratify/issues/856

## Type of change

Please delete options that are not relevant.

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Helm Chart Change (any edit/addition/update that is necessary for changes merged to the `main` branch)
- [ ] This change requires a documentation update

# How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Please also list any relevant details for your test configuration

I tested the error format in both add-on service and CLI tool.

1. Add-on service.
The service log would look like:
![image](https://github.com/deislabs/ratify/assets/6919333/f73db69f-5fe5-4a41-a241-ff02ebc45384)

2. CLI.
![image](https://github.com/deislabs/ratify/assets/6919333/19edf54b-c8cf-471e-9584-4c06bf7f61a8)

# Checklist:

- [ ] Does the affected code have corresponding tests?
- [ ] Are the changes documented, not just with inline documentation, but also with conceptual documentation such as an overview of a new feature, or task-based documentation like a tutorial? Consider if this change should be announced on your project blog.
- [ ] Does this introduce breaking changes that would require an announcement or bumping the major version?
- [ ] Do all new files have appropriate license header?

# Post Merge Requirements
- [ ] MAINTAINERS: manually trigger the "Publish Package" workflow after merging any PR that indicates `Helm Chart Change`


akashsinghal: Thanks for this quality work @binbin-li! Would it be possible to get a screenshot of what the new formatted logs look like? Same for the error message from GK and the CLI?
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/deislabs/ratify/pull/956?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deislabs) Report
Patch coverage: **`56.22%`** and project coverage change: **`+1.69%`** :tada:
> Comparison is base [(`fd9e33b`)](https://app.codecov.io/gh/deislabs/ratify/commit/fd9e33b2c838a2f97b4b9248901bace4539232fe?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deislabs) 56.87% compared to head [(`24e71bd`)](https://app.codecov.io/gh/deislabs/ratify/pull/956?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deislabs) 58.57%.
> Report is 7 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #956      +/-   ##
==========================================
+ Coverage   56.87%   58.57%   +1.69%     
==========================================
  Files          90       73      -17     
  Lines        5269     4362     -907     
==========================================
- Hits         2997     2555     -442     
+ Misses       1969     1571     -398     
+ Partials      303      236      -67     
```


| [Files Changed](https://app.codecov.io/gh/deislabs/ratify/pull/956?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deislabs) | Coverage Δ | |
|---|---|---|
| [pkg/common/oras/authprovider/authprovider.go](https://app.codecov.io/gh/deislabs/ratify/pull/956?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deislabs#diff-cGtnL2NvbW1vbi9vcmFzL2F1dGhwcm92aWRlci9hdXRocHJvdmlkZXIuZ28=) | `38.23% <0.00%> (-5.89%)` | :arrow_down: |
| [pkg/policyprovider/configpolicy/configpolicy.go](https://app.codecov.io/gh/deislabs/ratify/pull/956?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deislabs#diff-cGtnL3BvbGljeXByb3ZpZGVyL2NvbmZpZ3BvbGljeS9jb25maWdwb2xpY3kuZ28=) | `75.30% <0.00%> (-17.29%)` | :arrow_down: |
| [pkg/referrerstore/factory/factory.go](https://app.codecov.io/gh/deislabs/ratify/pull/956?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deislabs#diff-cGtnL3JlZmVycmVyc3RvcmUvZmFjdG9yeS9mYWN0b3J5Lmdv) | `47.69% <0.00%> (-9.24%)` | :arrow_down: |
| [pkg/referrerstore/oras/cache.go](https://app.codecov.io/gh/deislabs/ratify/pull/956?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deislabs#diff-cGtnL3JlZmVycmVyc3RvcmUvb3Jhcy9jYWNoZS5nbw==) | `72.72% <0.00%> (ø)` | |
| [pkg/verifier/factory/factory.go](https://app.codecov.io/gh/deislabs/ratify/pull/956?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deislabs#diff-cGtnL3ZlcmlmaWVyL2ZhY3RvcnkvZmFjdG9yeS5nbw==) | `42.18% <0.00%> (-18.75%)` | :arrow_down: |
| [pkg/verifier/plugin/plugin.go](https://app.codecov.io/gh/deislabs/ratify/pull/956?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deislabs#diff-cGtnL3ZlcmlmaWVyL3BsdWdpbi9wbHVnaW4uZ28=) | `56.94% <0.00%> (-13.89%)` | :arrow_down: |
| [httpserver/handlers.go](https://app.codecov.io/gh/deislabs/ratify/pull/956?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deislabs#diff-aHR0cHNlcnZlci9oYW5kbGVycy5nbw==) | `73.54% <6.66%> (-0.40%)` | :arrow_down: |
| [.../common/oras/authprovider/k8secret\_authprovider.go](https://app.codecov.io/gh/deislabs/ratify/pull/956?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deislabs#diff-cGtnL2NvbW1vbi9vcmFzL2F1dGhwcm92aWRlci9rOHNlY3JldF9hdXRocHJvdmlkZXIuZ28=) | `15.68% <7.14%> (ø)` | |
| [pkg/certificateprovider/azurekeyvault/provider.go](https://app.codecov.io/gh/deislabs/ratify/pull/956?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deislabs#diff-cGtnL2NlcnRpZmljYXRlcHJvdmlkZXIvYXp1cmVrZXl2YXVsdC9wcm92aWRlci5nbw==) | `42.67% <20.00%> (ø)` | |
| [pkg/referrerstore/oras/oras.go](https://app.codecov.io/gh/deislabs/ratify/pull/956?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deislabs#diff-cGtnL3JlZmVycmVyc3RvcmUvb3Jhcy9vcmFzLmdv) | `59.74% <20.00%> (-9.10%)` | :arrow_down: |
| ... and [13 more](https://app.codecov.io/gh/deislabs/ratify/pull/956?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deislabs) | |

... and [28 files with indirect coverage changes](https://app.codecov.io/gh/deislabs/ratify/pull/956/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deislabs)


</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/deislabs/ratify/pull/956?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deislabs).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deislabs).

susanshi: > Thanks for this quality work @binbin-li! Would it be possible to get a screenshot of what the new formatted logs look like? Same for the error message from GK and the CLI?

thanks the sample errors in the images.  Just to clarify , Is stack trace in every bad image report? stack trace is needed when something is wrong, i want to make sure when Ratify successfully run validation,we don't pass a stack trace on a bad image.
binbin-li: > Looks great! lets sync on the TSG

synced offline. thanks a lot for feedback @susanshi 

Patch:
diff --git a/cmd/ratify/main.go b/cmd/ratify/main.go
index 10f1373..862061b 100644
--- a/cmd/ratify/main.go
+++ b/cmd/ratify/main.go
@@ -25,8 +25,15 @@ import (
 	_ "github.com/deislabs/ratify/pkg/policyprovider/regopolicy"   // register regopolicy policy provider
 	_ "github.com/deislabs/ratify/pkg/referrerstore/oras"          // register oras referrer store
 	_ "github.com/deislabs/ratify/pkg/verifier/notation"           // register notation verifier
+	"github.com/sirupsen/logrus"
 )
 
+func init() {
+	logrus.SetFormatter(&logrus.TextFormatter{
+		DisableQuote: true,
+	})
+}
+
 func main() {
 	if err := cmd.Root.Execute(); err != nil {
 		os.Exit(1)
diff --git a/docs/reference/errors.md b/docs/reference/errors.md
new file mode 100644
index 0000000..78088c2
--- /dev/null
+++ b/docs/reference/errors.md
@@ -0,0 +1,63 @@
+# Errors in Ratify
+Ratify can generate various errors, either from its core workflow or from external/internal plugins. To facilitate easier debugging, Ratify will throw an error with a `code` property in most cases. This code can be used to identify the error and provide a more meaningful error message.
+
+## Error Codes
+### Errors from core workflow
+#### System errors
+| Code | Description | Trouble Shooting Guide |
+| ---- | ----------- | ---------------------- |
+| EXECUTOR_FAILURE | executor failure | Generic error returned when the executor fails to perform an operation. |
+| BAD_REQUEST | bad request | The request is invalid or malformed. Check the request body and headers for more details. |
+| AUTH_DENIED | auth denied | The authentication to required resource is denied. Please validate the credentials or configuration and check the detailed error. For auth configuration in oras store, please refer to [oras-auth-provider](oras-auth-provider.md).|
+| GET_CLUSTER_RESOURCE_FAILURE | get cluster resource failure | Ratify failed to get required resources from the cluster. Please validate if the resources exists in the cluster and the access is correctly assigned. |
+| DATA_DECODING_FAILURE | data decoding failure | Failed to decode data. Please verify the decoding data. |
+| DATA_ENCODING_FAILURE | data encoding failure | Failed to encode data. Please verify the encoding data. |
+
+#### Configuration errors
+| Code | Description | Trouble Shooting Guide |
+| ---- | ----------- | ---------------------- |
+| REFERENCE_INVALID | reference invalid | Ratify failed to parse the given reference. Please verify the reference is in the correct format following docker convention: https://docs.docker.com/engine/reference/commandline/images/ |
+| CACHE_NOT_SET | cache not set | The cache is not set successfully, please validate cache was created successfully during Ratify initialization. |
+| CONFIG_INVALID | config invalid | The config is invalid. Please validate your config. |
+| ENV_NOT_SET | env not set | The required environment is not set. Please set it up properly. |
+| HOST_NAME_INVALID | host name invalid | The registry hostname of given image or artifact is invalid. Please verify the registry hostname to ensure it can be correctly parsed |
+| NO_MATCHING_CREDENTIAL | no matching credential| Please verify the credentials is set up in K8s Secret. Please refer to [oras-auth-provider](./oras-auth-provider.md#3-kubernetes-secrets) for more details. |
+
+
+### Errors from external/built-in plugins
+
+#### Generic plugin errors
+| Code | Description | Trouble Shooting Guide |
+| ---- | ----------- | ---------------------- |
+| PLUGIN_INIT_FAILURE | plugin init failure | The plugin fails to be initialized. Please check error details and validate the plugin config is correctly provided. |
+| PLUGIN_NOT_FOUND | plugin not found | No plugin was found. Verify the required plugin is supported by Ratify and check the plugin name is entered correctly. |
+| DOWNLOAD_PLUGIN_FAILURE | download plugin failure | Failed to download plugin. Please verify the provided plugin configuration is correct and check the error details for further investigation. Refer to https://github.com/deislabs/ratify/blob/main/docs/reference/dynamic-plugins.md for more information. |
+| CERT_INVALID | cert invalid | The certificate is invalid. Please verify the provided inline certificates or certificates fetched from key vault are in valid format. Refer to https://github.com/deislabs/ratify/blob/main/docs/reference/crds/certificate-stores.md for more information. |
+| PROVIDER_NOT_FOUND | provider not found | No provider was found. Please verify that the necessary policy provider has been registered and that the provider's name has been entered correctly. |
+
+#### Verifier errors
+| Code | Description | Trouble Shooting Guide |
+| ---- | ----------- | ---------------------- |
+| VERIFY_REFERENCE_FAILURE | verify reference failure | Generic error returned when the verifier fails to verify the reference. Please check the error details for more information. |
+| VERIFY_SIGNATURE_FAILURE | verify signature failure | Verifier failed to verify signature. Please check the error details from the verifier plugin and refer to plugin's documentation for more details. |
+| SIGNATURE_NOT_FOUND | signature not found | No signature was found. Please validate the image has signatures attached. |
+
+#### Certificate Store errors
+
+| Code | Description  | Trouble Shooting Guide |
+| ---- | -----------  | ---------------------- |
+| KEY_VAULT_OPERATION_FAILURE | key vault operation failed | Please validate correct key vault configuration is provided or check the error details for further investigation. Please review steps in [ratify-on-azure](../quickstarts/ratify-on-azure.md) for configuring Key Vault. | 
+
+#### Referrer Store errors
+| Code | Description  | Trouble Shooting Guide |
+| ---- | -----------  | ---------------------- |
+| LIST_REFERRERS_FAILURE | list referrers failure | Referrer store fails to list the referrers. Refer to https://github.com/deislabs/ratify/blob/main/docs/reference/store.md#listreferrers for more details. |
+| GET_SUBJECT_DESCRIPTOR_FAILURE | get subject descriptor failure | Referrer store fails to get the subject descriptor. Refer to https://github.com/deislabs/ratify/blob/main/docs/reference/store.md#getsubjectdescriptor for more details. |
+| GET_REFERRER_MANIFEST_FAILURE | get reference manifest failure | Referrer store fails to get the reference manifest. Refer to https://github.com/deislabs/ratify/blob/main/docs/reference/store.md#getreferencemanifest for more details. |
+| GET_BLOB_CONTENT_FAILURE | get blob content failure | Referrer store fails to get the blob content. | Check the original error for more details. |
+| REFERRER_STORE_FAILURE | referrer store failure | Referrer store fails to get the blob content. Refer to https://github.com/deislabs/ratify/blob/main/docs/reference/store.md#getblobcontent for more details. |
+| CREATE_REPOSITORY_FAILURE | create repository failure | Failed to create repository. Please verify the repository config is configured correctly and check error details for more information. |
+| REPOSITORY_OPERATION_FAILURE | repository operation failure | The operation to the repository failed. Please check the error details for more information. |
+| MANIFEST_INVALID | manifest invalid | The manifest is invalid. Please validate the manifest is correctly formatted. |
+| REFERRERS_NOT_FOUND | referrers not found | No referrers are found. Please verify the subject has attached expected artifacts and refer to https://github.com/deislabs/ratify/blob/main/docs/reference/store.md to investigate Referrer Store configuration. |
+
diff --git a/pkg/executor/core/errors.go b/errors/azure.go
similarity index 61%
rename from pkg/executor/core/errors.go
rename to errors/azure.go
index 4961a28..b77e51e 100644
--- a/pkg/executor/core/errors.go
+++ b/errors/azure.go
@@ -13,11 +13,10 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-package core
+package errors
 
-import "errors"
-
-var (
-	// ErrReferrersNotFound is thrown when there aren't any references for an artifact
-	ErrReferrersNotFound = errors.New("no referrers found for this artifact")
+const (
+	AKVLink                   = "https://learn.microsoft.com/en-us/azure/key-vault/general/overview"
+	AzureWorkloadIdentityLink = "https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview"
+	AzureManagedIdentityLink  = "https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview"
 )
diff --git a/errors/errors.go b/errors/errors.go
new file mode 100644
index 0000000..f27e9b0
--- /dev/null
+++ b/errors/errors.go
@@ -0,0 +1,120 @@
+/*
+Copyright The Ratify Authors.
+Licensed 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 errors
+
+const (
+	NotationSpecLink   = "https://github.com/notaryproject/notaryproject/tree/main/specs"
+	OrasLink           = "https://oras.land/"
+	AuthProviderLink   = "https://github.com/deislabs/ratify/blob/main/docs/reference/oras-auth-provider.md"
+	PolicyProviderLink = "https://github.com/deislabs/ratify/blob/main/docs/reference/providers.md#policy-providers"
+)
+
+var (
+	// ErrorCodeUnknown is a generic error that can be used as a last
+	// resort if there is no situation-specific error message that can be used
+	ErrorCodeUnknown = Register("errcode", ErrorDescriptor{
+		Value:       "UNKNOWN",
+		Message:     "unknown error",
+		Description: `Generic error returned when the error does not have an API classification.`,
+	})
+
+	// ErrorCodeExecutorFailure is returned when a generic error happen in
+	// executor.
+	ErrorCodeExecutorFailure = Register("errcode", ErrorDescriptor{
+		Value:       "EXECUTOR_FAILURE",
+		Message:     "executor failure",
+		Description: `Generic error returned when the executor fails to perform an operation. Please check the error details for more information.`,
+	})
+
+	// ErrorCodeBadRequest is returned if the request is not valid.
+	ErrorCodeBadRequest = Register("errcode", ErrorDescriptor{
+		Value:       "BAD_REQUEST",
+		Message:     `bad request`,
+		Description: `The request is invalid or malformed. Check the request body and headers for more details.`,
+	})
+
+	// ErrorCodeReferenceInvalid is returned if provided image reference is invalid.
+	ErrorCodeReferenceInvalid = Register("errcode", ErrorDescriptor{
+		Value:       "REFERENCE_INVALID",
+		Message:     "reference invalid",
+		Description: `Ratify failed to parse the given reference. Please verify the reference is in the correct format following docker convention: https://docs.docker.com/engine/reference/commandline/images/`,
+	})
+
+	// ErrorCodeCacheNotSet is returned if cache is not set successfully.
+	ErrorCodeCacheNotSet = Register("errcode", ErrorDescriptor{
+		Value:       "CACHE_NOT_SET",
+		Message:     "cache not set",
+		Description: `The cache is not set successfully. Check the error details.`,
+	})
+
+	// ErrorCodeConfigInvalid is returned if provided configuration is invalid.
+	ErrorCodeConfigInvalid = Register("errcode", ErrorDescriptor{
+		Value:       "CONFIG_INVALID",
+		Message:     "config invalid",
+		Description: `The config is invalid. Please validate your config.`,
+	})
+
+	// ErrorCodeAuthDenied is returned if authentication is denied.
+	ErrorCodeAuthDenied = Register("errcode", ErrorDescriptor{
+		Value:       "AUTH_DENIED",
+		Message:     "auth denied",
+		Description: `The authentication to required resource is denied. Please validate the credentials or configuration and check the detailed error.`,
+	})
+
+	// ErrorCodeEnvNotSet is returned if some environment variable is not set.
+	ErrorCodeEnvNotSet = Register("errcode", ErrorDescriptor{
+		Value:       "ENV_NOT_SET",
+		Message:     "env not set",
+		Description: `The required environment is not set. Please set it up properly.`,
+	})
+
+	// ErrorCodeGetClusterResourceFailure is returned if Ratify failed to get
+	// required resources from the cluster.
+	ErrorCodeGetClusterResourceFailure = Register("errcode", ErrorDescriptor{
+		Value:       "GET_CLUSTER_RESOURCE_FAILURE",
+		Message:     "get cluster resource failure",
+		Description: "Ratify failed to get required resources from the cluster. Please validate if the resources exists in the cluster and the access is correctly assigned.",
+	})
+
+	// ErrorCodeHostNameInvalid is returned when parsed hostName is invalid.
+	ErrorCodeHostNameInvalid = Register("errcode", ErrorDescriptor{
+		Value:       "HOST_NAME_INVALID",
+		Message:     "host name invalid",
+		Description: "The registry hostname of given image or artifact is invalid. Please verify the registry hostname to ensure it can be correctly parsed",
+	})
+
+	// ErrorCodeNoMatchingCredential is returned if authProvider cannot find
+	// matching credentials.
+	ErrorCodeNoMatchingCredential = Register("errcode", ErrorDescriptor{
+		Value:       "NO_MATCHING_CREDENTIAL",
+		Message:     "no matching credential",
+		Description: "No matching credential is found. Please verify the credentials is set up in K8s Secret.",
+	})
+
+	// ErrorCodeDataDecodingFailure is returned when it fails to decode data.
+	ErrorCodeDataDecodingFailure = Register("errcode", ErrorDescriptor{
+		Value:       "DATA_DECODING_FAILURE",
+		Message:     "data decoding failure",
+		Description: "Failed to decode data. Please verify the decoding data.",
+	})
+
+	// ErrorCodeDataEncodingFailure is returned when it fails to encode data.
+	ErrorCodeDataEncodingFailure = Register("errcode", ErrorDescriptor{
+		Value:       "DATA_ENCODING_FAILURE",
+		Message:     "data encoding failure",
+		Description: "Failed to encode data. Please verify the encoding data.",
+	})
+)
diff --git a/errors/pluginerrors.go b/errors/pluginerrors.go
new file mode 100644
index 0000000..e713f10
--- /dev/null
+++ b/errors/pluginerrors.go
@@ -0,0 +1,163 @@
+/*
+Copyright The Ratify Authors.
+Licensed 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 errors
+
+var (
+	// errors related to Verifier plugins
+
+	// ErrorCodeVerifyReferenceFailure is returned when verifier plugin fails to
+	// to verify given reference.
+	ErrorCodeVerifyReferenceFailure = Register("errcode", ErrorDescriptor{
+		Value:       "VERIFY_REFERENCE_FAILURE",
+		Message:     "verify reference failure",
+		Description: `Verifier fails to verify the reference. Please check the error details for more information.`,
+	})
+
+	// ErrorCodeVerifySignatureFailure is returned when verifier plugin fails
+	// to verify attached signature.
+	ErrorCodeVerifySignatureFailure = Register("errcode", ErrorDescriptor{
+		Value:       "VERIFY_SIGNATURE_FAILURE",
+		Message:     "verify signature failure",
+		Description: "Verifier failed to verify signature. Please check the error details from the verifier plugin and refer to plugin's documentation for more details.",
+	})
+
+	// ErrorCodeSignatureNotFound is returned when verifier cannot find a
+	// signature.
+	ErrorCodeSignatureNotFound = Register("errcode", ErrorDescriptor{
+		Value:       "SIGNATURE_NOT_FOUND",
+		Message:     "signature not found",
+		Description: "No signature was found. Please validate the verifying artifact has attached any expected signatures.",
+	})
+
+	// errors related to Referrer Store plugins
+
+	// ErrorCodeListReferrersFailure is returned when ListReferrers API fails.
+	ErrorCodeListReferrersFailure = Register("errcode", ErrorDescriptor{
+		Value:       "LIST_REFERRERS_FAILURE",
+		Message:     "list referrers failure",
+		Description: `Referrer store fails to list the referrers. Refer to https://github.com/deislabs/ratify/blob/main/docs/reference/store.md#listreferrers for more details.`,
+	})
+
+	// ErrorCodeGetSubjectDescriptorFailure is returned when GetSubjectDescriptor
+	// API fails.
+	ErrorCodeGetSubjectDescriptorFailure = Register("errcode", ErrorDescriptor{
+		Value:       "GET_SUBJECT_DESCRIPTOR_FAILURE",
+		Message:     "get subject descriptor failure",
+		Description: `Referrer store fails to get the subject descriptor. Refer to https://github.com/deislabs/ratify/blob/main/docs/reference/store.md#getsubjectdescriptor for more details.`,
+	})
+
+	// ErrorCodeGetReferenceManifestFailure is returned when GetReferenceManifest
+	// API fails.
+	ErrorCodeGetReferenceManifestFailure = Register("errcode", ErrorDescriptor{
+		Value:       "GET_REFERRER_MANIFEST_FAILURE",
+		Message:     "get reference manifest failure",
+		Description: `Referrer store fails to get the reference manifest. Refer to https://github.com/deislabs/ratify/blob/main/docs/reference/store.md#getreferencemanifest for more details.`,
+	})
+
+	// ErrorCodeGetBlobContentFailure is returned when GetBlobContent API fails.
+	ErrorCodeGetBlobContentFailure = Register("errcode", ErrorDescriptor{
+		Value:       "GET_BLOB_CONTENT_FAILURE",
+		Message:     "get blob content failure",
+		Description: `Referrer store fails to get the blob content. Refer to https://github.com/deislabs/ratify/blob/main/docs/reference/store.md#getblobcontent for more details.`,
+	})
+
+	// ErrorCodeReferrerStoreFailure is returned when a generic error happen in
+	// ReferrerStore.
+	ErrorCodeReferrerStoreFailure = Register("errcode", ErrorDescriptor{
+		Value:       "REFERRER_STORE_FAILURE",
+		Message:     "referrer store failure",
+		Description: `Referrer store fails to perform an operation.`,
+	})
+
+	// ErrorCodeCreateRepositoryFailure is returned when Referrer Store fails to
+	// create a repository object.
+	ErrorCodeCreateRepositoryFailure = Register("errcode", ErrorDescriptor{
+		Value:       "CREATE_REPOSITORY_FAILURE",
+		Message:     "create repository failure",
+		Description: "Failed to create repository. Please verify the repository config is configured correctly and check error details for more information.",
+	})
+
+	// ErrorCodeRepositoryOperationFailure is returned when a repository
+	// operation fails.
+	ErrorCodeRepositoryOperationFailure = Register("errcode", ErrorDescriptor{
+		Value:       "REPOSITORY_OPERATION_FAILURE",
+		Message:     "repository operation failure",
+		Description: `The operation to the repository failed. Please check the error details for more information.`,
+	})
+
+	// ErrorCodeManifestInvalid is returned if fetched manifest is invalid.
+	ErrorCodeManifestInvalid = Register("errcode", ErrorDescriptor{
+		Value:       "MANIFEST_INVALID",
+		Message:     "manifest invalid",
+		Description: `The manifest is invalid. Please validate the manifest is correctly formatted.`,
+	})
+
+	// ErrorCodeReferrersNotFound is returned if there is no ReferrerStore set.
+	ErrorCodeReferrersNotFound = Register("errcode", ErrorDescriptor{
+		Value:       "REFERRERS_NOT_FOUND",
+		Message:     "referrers not found",
+		Description: "No referrers are found. Please verify the subject has attached expected artifacts and refer to https://github.com/deislabs/ratify/blob/main/docs/reference/store.md to investigate Referrer Store configuration.",
+	})
+
+	// Generic errors happen in plugins
+
+	// ErrorCodePluginInitFailure is returned when executor or controller fails
+	// to initialize a plugin.
+	ErrorCodePluginInitFailure = Register("errcode", ErrorDescriptor{
+		Value:       "PLUGIN_INIT_FAILURE",
+		Message:     "plugin init failure",
+		Description: "The plugin fails to be initialized. Please check error details and validate the plugin config is correctly provided.",
+	})
+
+	// ErrorCodePluginNotFound is returned when the executor cannot find the
+	// required external plugin.
+	ErrorCodePluginNotFound = Register("errcode", ErrorDescriptor{
+		Value:       "PLUGIN_NOT_FOUND",
+		Message:     "plugin not found",
+		Description: "No plugin was found. Verify the required plugin is supported by Ratify and check the plugin name is entered correctly.",
+	})
+
+	// ErrorCodeDownloadPluginFailure is returned when executor fails to
+	// download a required external plugin.
+	ErrorCodeDownloadPluginFailure = Register("errcode", ErrorDescriptor{
+		Value:       "DOWNLOAD_PLUGIN_FAILURE",
+		Message:     "download plugin failure",
+		Description: "Failed to download plugin. Please verify the provided plugin configuration is correct and check the error details for further investigation. Refer to https://github.com/deislabs/ratify/blob/main/docs/reference/dynamic-plugins.md for more information.",
+	})
+
+	// ErrorCodeCertInvalid is returned when provided certificates are invalid.
+	ErrorCodeCertInvalid = Register("errcode", ErrorDescriptor{
+		Value:       "CERT_INVALID",
+		Message:     "cert invalid",
+		Description: "The certificate is invalid. Please verify the provided inline certificates or certificates fetched from key vault are in valid format. Refer to https://github.com/deislabs/ratify/blob/main/docs/reference/crds/certificate-stores.md for more information.",
+	})
+
+	// ErrorCodePolicyProviderNotFound is returned when a policy provider cannot
+	// be found.
+	ErrorCodePolicyProviderNotFound = Register("errcode", ErrorDescriptor{
+		Value:       "POLICY_PROVIDER_NOT_FOUND",
+		Message:     "policy provider not found",
+		Description: "No provider was found. Please verify that the necessary policy provider has been registered and that the provider's name has been entered correctly.",
+	})
+
+	// ErrorCodeKeyVaultOperationFailure is returned when a key vault operation
+	// fails.
+	ErrorCodeKeyVaultOperationFailure = Register("errcode", ErrorDescriptor{
+		Value:       "KEY_VAULT_OPERATION_FAILURE",
+		Message:     "Key vault operation failed",
+		Description: "Key vault operation failed. Please validate correct key vault configuration is provided or check the error details for further investigation.",
+	})
+)
diff --git a/errors/types.go b/errors/types.go
new file mode 100644
index 0000000..09ea9a3
--- /dev/null
+++ b/errors/types.go
@@ -0,0 +1,295 @@
+/*
+Copyright The Ratify Authors.
+Licensed 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 errors
+
+import (
+	"errors"
+	"fmt"
+	"runtime"
+	"strings"
+	"sync"
+)
+
+const (
+	EmptyLink       = ""
+	PrintStackTrace = true
+	HideStackTrace  = false
+)
+
+var (
+	nextCode     = 1000
+	registerLock sync.Mutex
+)
+
+var (
+	errorCodeToDescriptors = map[ErrorCode]ErrorDescriptor{}
+	idToDescriptors        = map[string]ErrorDescriptor{}
+	groupToDescriptors     = map[string][]ErrorDescriptor{}
+)
+
+type ComponentType string
+
+const (
+	Verifier       ComponentType = "verifier"
+	ReferrerStore  ComponentType = "referrerStore"
+	Policy         ComponentType = "policy"
+	Executor       ComponentType = "executor"
+	Cache          ComponentType = "cache"
+	AuthProvider   ComponentType = "authProvider"
+	PolicyProvider ComponentType = "policyProvider"
+	CertProvider   ComponentType = "certProvider"
+)
+
+// ErrorCode represents the error type. The errors are serialized via strings
+// and the integer format may change and should *never* be exported.
+type ErrorCode int
+
+// Error provides a wrapper around ErrorCode with extra Details provided.
+type Error struct {
+	OriginalError error         `json:"originalError,omitempty"`
+	Code          ErrorCode     `json:"code"`
+	Message       string        `json:"message"`
+	Detail        interface{}   `json:"detail,omitempty"`
+	ComponentType ComponentType `json:"componentType,omitempty"`
+	PluginName    string        `json:"pluginName,omitempty"`
+	LinkToDoc     string        `json:"linkToDoc,omitempty"`
+	Stack         string        `json:"stack,omitempty"`
+}
+
+// ErrorDescriptor provides relevant information about a given error code.
+type ErrorDescriptor struct {
+	// Code is the error code that this descriptor describes.
+	Code ErrorCode
+
+	// Value provides a unique, string key, often captilized with
+	// underscores, to identify the error code. This value is used as the
+	// keyed value when serializing api errors.
+	Value string
+
+	// Message is a short, human readable description of the error condition
+	// included in API responses.
+	Message string
+
+	// Description provides a complete account of the errors purpose, suitable
+	// for use in documentation.
+	Description string
+
+	// ComponentType specifies the type of the component that the error is from.
+	ComponentType ComponentType
+
+	// PluginName specifies the name of the plugin that the error is from.
+	PluginName string
+}
+
+var emptyError = Error{}
+
+// ErrorCode returns itself
+func (ec ErrorCode) ErrorCode() ErrorCode {
+	return ec
+}
+
+// Error returns the ID/Value
+func (ec ErrorCode) Error() string {
+	// NOTE(stevvooe): Cannot use message here since it may have unpopulated args.
+	return strings.ToLower(strings.Replace(ec.String(), "_", " ", -1))
+}
+
+// Descriptor returns the descriptor for the error code.
+func (ec ErrorCode) Descriptor() ErrorDescriptor {
+	d, ok := errorCodeToDescriptors[ec]
+
+	if !ok {
+		return ErrorCodeUnknown.Descriptor()
+	}
+
+	return d
+}
+
+// Message returned the human-readable error message for this error code.
+func (ec ErrorCode) Message() string {
+	return ec.Descriptor().Message
+}
+
+// String returns the canonical identifier for this error code.
+func (ec ErrorCode) String() string {
+	return ec.Descriptor().Value
+}
+
+// WithDetail returns a new Error object with details about the error.
+func (ec ErrorCode) WithDetail(detail interface{}) Error {
+	return newError(ec, ec.Message()).WithDetail(detail)
+}
+
+// WithError returns a new Error object with original error.
+func (ec ErrorCode) WithError(err error) Error {
+	return newError(ec, ec.Message()).WithError(err)
+}
+
+// WithComponentType returns a new Error object with ComponentType set.
+func (ec ErrorCode) WithComponentType(componentType ComponentType) Error {
+	return newError(ec, ec.Message()).WithComponentType(componentType)
+}
+
+// WithLinkToDoc returns a new Error object with attached link to the documentation.
+func (ec ErrorCode) WithLinkToDoc(link string) Error {
+	return newError(ec, ec.Message()).WithLinkToDoc(link)
+}
+
+// WithPluginName returns a new Error object with pluginName set.
+func (ec ErrorCode) WithPluginName(pluginName string) Error {
+	return newError(ec, ec.Message()).WithPluginName(pluginName)
+}
+
+// NewError returns a new Error object.
+func (ec ErrorCode) NewError(componentType ComponentType, pluginName, link string, err error, detail interface{}, printStackTrace bool) Error {
+	stack := ""
+	if printStackTrace {
+		stack = getStackTrace()
+	}
+	return Error{
+		Code:          ec,
+		Message:       ec.Message(),
+		OriginalError: err,
+		Detail:        detail,
+		ComponentType: componentType,
+		PluginName:    pluginName,
+		LinkToDoc:     link,
+		Stack:         stack,
+	}
+}
+
+func newError(code ErrorCode, message string) Error {
+	return Error{
+		Code:    code,
+		Message: message,
+	}
+}
+
+// Is returns true if the error is the same type of the target error.
+func (e Error) Is(target error) bool {
+	t := &Error{}
+	if errors.As(target, t) {
+		return e.Code.ErrorCode() == t.Code.ErrorCode()
+	}
+	return false
+}
+
+// ErrorCode returns the ID/Value of this Error
+func (e Error) ErrorCode() ErrorCode {
+	return e.Code
+}
+
+// Unwrap returns the original error
+func (e Error) Unwrap() error {
+	return e.OriginalError
+}
+
+// Error returns a human readable representation of the error.
+func (e Error) Error() string {
+	var errStr string
+	if e.OriginalError != nil {
+		errStr += fmt.Sprintf("Original Error: (%s), ", e.OriginalError.Error())
+	}
+
+	errStr += fmt.Sprintf("Error: %s, Code: %s", e.Message, e.Code.String())
+
+	if e.PluginName != "" {
+		errStr += fmt.Sprintf(", Plugin Name: %s", e.PluginName)
+	}
+
+	if e.ComponentType != "" {
+		errStr += fmt.Sprintf(", Component Type: %s", e.ComponentType)
+	}
+
+	if e.LinkToDoc != "" {
+		errStr += fmt.Sprintf(", Documentation: %s", e.LinkToDoc)
+	}
+
+	if e.Detail != nil {
+		errStr += fmt.Sprintf(", Detail: %v", e.Detail)
+	}
+
+	if e.Stack != "" {
+		errStr += fmt.Sprintf(", Stack trace: %s", e.Stack)
+	}
+
+	return errStr
+}
+
+// WithDetail will return a new Error, based on the current one, but with
+// some Detail info added
+func (e Error) WithDetail(detail interface{}) Error {
+	e.Detail = detail
+	return e
+}
+
+// WithPluginName returns a new Error object with pluginName set.
+func (e Error) WithPluginName(pluginName string) Error {
+	e.PluginName = pluginName
+	return e
+}
+
+// WithComponentType returns a new Error object with ComponentType set.
+func (e Error) WithComponentType(componentType ComponentType) Error {
+	e.ComponentType = componentType
+	return e
+}
+
+// WithError returns a new Error object with original error.
+func (e Error) WithError(err error) Error {
+	e.OriginalError = err
+	return e
+}
+
+// WithLinkToDoc returns a new Error object attached with link to documentation.
+func (e Error) WithLinkToDoc(link string) Error {
+	e.LinkToDoc = link
+	return e
+}
+
+// IsEmpty returns true if the error is empty.
+func (e Error) IsEmpty() bool {
+	return e == emptyError
+}
+
+func getStackTrace() string {
+	stack := make([]byte, 4096)
+	n := runtime.Stack(stack, false)
+	return string(stack[:n])
+}
+
+// Register will make the passed-in error known to the environment and
+// return a new ErrorCode
+func Register(group string, descriptor ErrorDescriptor) ErrorCode {
+	registerLock.Lock()
+	defer registerLock.Unlock()
+
+	descriptor.Code = ErrorCode(nextCode)
+
+	if _, ok := idToDescriptors[descriptor.Value]; ok {
+		panic(fmt.Sprintf("ErrorValue %q is already registered", descriptor.Value))
+	}
+	if _, ok := errorCodeToDescriptors[descriptor.Code]; ok {
+		panic(fmt.Sprintf("ErrorCode %v is already registered", descriptor.Code))
+	}
+
+	groupToDescriptors[group] = append(groupToDescriptors[group], descriptor)
+	errorCodeToDescriptors[descriptor.Code] = descriptor
+	idToDescriptors[descriptor.Value] = descriptor
+
+	nextCode++
+	return descriptor.Code
+}
diff --git a/httpserver/handlers.go b/httpserver/handlers.go
index d5c07df..44426ca 100644
--- a/httpserver/handlers.go
+++ b/httpserver/handlers.go
@@ -24,6 +24,7 @@ import (
 	"sync"
 	"time"
 
+	"github.com/deislabs/ratify/errors"
 	"github.com/deislabs/ratify/pkg/cache"
 	"github.com/deislabs/ratify/pkg/executor"
 	"github.com/deislabs/ratify/pkg/executor/types"
@@ -97,7 +98,8 @@ func (server *Server) verify(ctx context.Context, w http.ResponseWriter, r *http
 			}
 			if found && cacheResponse != "" {
 				if err := json.Unmarshal([]byte(cacheResponse), &result); err != nil {
-					logrus.Warningf("unable to unmarshal cache entry for subject %v: %v", resolvedSubjectReference, err)
+					err = errors.ErrorCodeDataDecodingFailure.WithError(err).WithDetail(fmt.Sprintf("unable to unmarshal cache entry for subject %v", resolvedSubjectReference))
+					logrus.Warning(err)
 				} else {
 					cacheHit = true
 					logrus.Debugf("cache hit for subject %v", resolvedSubjectReference)
@@ -109,7 +111,7 @@ func (server *Server) verify(ctx context.Context, w http.ResponseWriter, r *http
 				}
 
 				if result, err = server.GetExecutor().VerifySubject(ctx, verifyParameters); err != nil {
-					returnItem.Error = err.Error()
+					returnItem.Error = errors.ErrorCodeExecutorFailure.WithError(err).WithComponentType(errors.Executor).Error()
 					return
 				}
 
@@ -121,7 +123,7 @@ func (server *Server) verify(ctx context.Context, w http.ResponseWriter, r *http
 				}
 
 				if res, err := json.MarshalIndent(result, "", "  "); err == nil {
-					fmt.Println(string(res))
+					logrus.Infof("verify result for subject %s: %s", resolvedSubjectReference, string(res))
 				}
 			}
 
@@ -144,13 +146,13 @@ func (server *Server) mutate(ctx context.Context, w http.ResponseWriter, r *http
 
 	body, err := io.ReadAll(r.Body)
 	if err != nil {
-		return fmt.Errorf("unable to read request body: %w", err)
+		return errors.ErrorCodeBadRequest.WithError(err).WithDetail("unable to read request body")
 	}
 
 	// parse request body
 	var providerRequest externaldata.ProviderRequest
 	if err = json.Unmarshal(body, &providerRequest); err != nil {
-		return fmt.Errorf("unable to unmarshal request body: %w", err)
+		return errors.ErrorCodeBadRequest.WithError(err).WithDetail("unable to unmarshal request body")
 	}
 
 	results := make([]externaldata.Item, 0)
@@ -174,9 +176,9 @@ func (server *Server) mutate(ctx context.Context, w http.ResponseWriter, r *http
 			}()
 			parsedReference, err := pkgUtils.ParseSubjectReference(image)
 			if err != nil {
-				errMessage := fmt.Sprintf("failed to mutate image reference %s: %v", image, err)
-				logrus.Error(errMessage)
-				returnItem.Error = errMessage
+				err = errors.ErrorCodeReferenceInvalid.WithError(err).WithDetail(fmt.Sprintf("failed to parse image reference %s", image))
+				logrus.Error(err)
+				returnItem.Error = err.Error()
 				return
 			}
 
@@ -189,16 +191,15 @@ func (server *Server) mutate(ctx context.Context, w http.ResponseWriter, r *http
 					}
 				}
 				if selectedStore == nil {
-					errMessage := fmt.Sprintf("failed to mutate image reference %s: could not find matching store %s", image, server.MutationStoreName)
-					logrus.Error(errMessage)
-					returnItem.Error = errMessage
+					err := errors.ErrorCodeReferrerStoreFailure.WithDetail(fmt.Sprintf("failed to mutate image reference %s: could not find matching store %s", image, server.MutationStoreName)).WithComponentType(errors.ReferrerStore)
+					logrus.Error(err)
+					returnItem.Error = err.Error()
 					return
 				}
 				descriptor, err := selectedStore.GetSubjectDescriptor(ctx, parsedReference)
 				if err != nil {
-					errMessage := fmt.Sprintf("failed to mutate image reference %s: %v", image, err)
-					logrus.Error(errMessage)
-					returnItem.Error = errMessage
+					err = errors.ErrorCodeGetSubjectDescriptorFailure.NewError(errors.ReferrerStore, selectedStore.Name(), errors.EmptyLink, err, fmt.Sprintf("failed to get subject descriptor for image %s", image), errors.HideStackTrace)
+					returnItem.Error = err.Error()
 					return
 				}
 				returnItem.Value = fmt.Sprintf("%s@%s", parsedReference.Path, descriptor.Digest.String())
diff --git a/pkg/certificateprovider/azurekeyvault/provider.go b/pkg/certificateprovider/azurekeyvault/provider.go
index 2a4a643..6e4d39c 100644
--- a/pkg/certificateprovider/azurekeyvault/provider.go
+++ b/pkg/certificateprovider/azurekeyvault/provider.go
@@ -27,6 +27,7 @@ import (
 	"strings"
 	"time"
 
+	re "github.com/deislabs/ratify/errors"
 	"github.com/deislabs/ratify/pkg/certificateprovider"
 	"github.com/deislabs/ratify/pkg/certificateprovider/azurekeyvault/types"
 	"github.com/deislabs/ratify/pkg/metrics"
@@ -34,7 +35,6 @@ import (
 
 	kv "github.com/Azure/azure-sdk-for-go/services/keyvault/v7.1/keyvault"
 	"github.com/Azure/go-autorest/autorest/azure"
-	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 	"gopkg.in/yaml.v2"
 )
@@ -66,34 +66,34 @@ func (s *akvCertProvider) GetCertificates(ctx context.Context, attrib map[string
 	workloadIdentityClientID := types.GetClientID(attrib)
 
 	if keyvaultURI == "" {
-		return nil, nil, fmt.Errorf("keyvaultUri is not set")
+		return nil, nil, re.ErrorCodeConfigInvalid.NewError(re.CertProvider, providerName, re.AKVLink, nil, "keyvaultUri is not set", re.HideStackTrace)
 	}
 	if tenantID == "" {
-		return nil, nil, fmt.Errorf("tenantID is not set")
+		return nil, nil, re.ErrorCodeConfigInvalid.NewError(re.CertProvider, providerName, re.AKVLink, nil, "tenantID is not set", re.HideStackTrace)
 	}
 	if workloadIdentityClientID == "" {
-		return nil, nil, fmt.Errorf("clientID is not set")
+		return nil, nil, re.ErrorCodeConfigInvalid.NewError(re.CertProvider, providerName, re.AKVLink, nil, "clientID is not set", re.HideStackTrace)
 	}
 
 	azureCloudEnv, err := parseAzureEnvironment(cloudName)
 	if err != nil {
-		return nil, nil, fmt.Errorf("cloudName %s is not valid, error: %w", cloudName, err)
+		return nil, nil, re.ErrorCodeConfigInvalid.NewError(re.CertProvider, providerName, re.EmptyLink, nil, fmt.Sprintf("cloudName %s is not valid", cloudName), re.HideStackTrace)
 	}
 
 	keyVaultCerts, err := getKeyvaultRequestObj(attrib)
 	if err != nil {
-		return nil, nil, fmt.Errorf("failed to get keyvault request object from provider attributes, error: %w", err)
+		return nil, nil, re.ErrorCodeConfigInvalid.NewError(re.CertProvider, providerName, re.AKVLink, err, "failed to get keyvault request object from provider attributes", re.HideStackTrace)
 	}
 
 	if len(keyVaultCerts) == 0 {
-		return nil, nil, fmt.Errorf("no keyvault certificate configured")
+		return nil, nil, re.ErrorCodeConfigInvalid.NewError(re.CertProvider, providerName, re.EmptyLink, nil, "no keyvault certificate configured", re.PrintStackTrace)
 	}
 
 	logrus.Debugf("vaultURI %s", keyvaultURI)
 
 	kvClient, err := initializeKvClient(ctx, azureCloudEnv.KeyVaultEndpoint, tenantID, workloadIdentityClientID)
 	if err != nil {
-		return nil, nil, fmt.Errorf("failed to get keyvault client, error: %w", err)
+		return nil, nil, re.ErrorCodePluginInitFailure.NewError(re.CertProvider, providerName, re.AKVLink, err, "failed to get keyvault client", re.HideStackTrace)
 	}
 
 	certs := []*x509.Certificate{}
@@ -137,21 +137,21 @@ func getKeyvaultRequestObj(attrib map[string]string) ([]types.KeyVaultCertificat
 
 	certificatesStrings := types.GetCertificates(attrib)
 	if certificatesStrings == "" {
-		return nil, fmt.Errorf("certificates is not set")
+		return nil, re.ErrorCodeConfigInvalid.NewError(re.CertProvider, providerName, re.EmptyLink, nil, "certificates is not set", re.HideStackTrace)
 	}
 
 	logrus.Debugf("certificates string defined in ratify certStore class, certificates %v", certificatesStrings)
 
 	objects, err := types.GetCertificatesArray(certificatesStrings)
 	if err != nil {
-		return nil, fmt.Errorf("failed to yaml unmarshal objects, error: %w", err)
+		return nil, re.ErrorCodeDataDecodingFailure.NewError(re.CertProvider, providerName, re.EmptyLink, err, "failed to yaml unmarshal objects", re.HideStackTrace)
 	}
 	logrus.Debugf("unmarshaled objects yaml, objectsArray %v", objects.Array)
 
 	for i, object := range objects.Array {
 		var keyVaultCert types.KeyVaultCertificate
 		if err = yaml.Unmarshal([]byte(object), &keyVaultCert); err != nil {
-			return nil, fmt.Errorf("unmarshal failed for keyVaultCerts at index %d, error: %w", i, err)
+			return nil, re.ErrorCodeDataDecodingFailure.NewError(re.CertProvider, providerName, re.EmptyLink, err, fmt.Sprintf("unmarshal failed for keyVaultCerts at index: %d", i), re.PrintStackTrace)
 		}
 		// remove whitespace from all fields in keyVaultCert
 		formatKeyVaultCertificate(&keyVaultCert)
@@ -209,12 +209,12 @@ func initializeKvClient(ctx context.Context, keyVaultEndpoint, tenantID, clientI
 
 	err := kvClient.AddToUserAgent("ratify")
 	if err != nil {
-		return nil, fmt.Errorf("failed to add user agent to keyvault client, error: %w", err)
+		return nil, re.ErrorCodeConfigInvalid.NewError(re.CertProvider, providerName, re.AKVLink, err, "failed to add user agent to keyvault client", re.PrintStackTrace)
 	}
 
 	kvClient.Authorizer, err = getAuthorizerForWorkloadIdentity(ctx, tenantID, clientID, kvEndpoint)
 	if err != nil {
-		return nil, fmt.Errorf("failed to get authorizer for keyvault client, error: %w", err)
+		return nil, re.ErrorCodeAuthDenied.NewError(re.CertProvider, providerName, re.AKVLink, err, "failed to get authorizer for keyvault client", re.PrintStackTrace)
 	}
 	return &kvClient, nil
 }
@@ -223,7 +223,7 @@ func initializeKvClient(ctx context.Context, keyVaultEndpoint, tenantID, clientI
 // In a certificate chain scenario, all certificates from root to leaf will be returned
 func getCertsFromSecretBundle(secretBundle kv.SecretBundle, certName string) ([]*x509.Certificate, []map[string]string, error) {
 	if secretBundle.ContentType == nil || secretBundle.Value == nil || secretBundle.ID == nil {
-		return nil, nil, errors.Errorf("found invalid secret bundle for certificate  %s, contentType, value, and id must not be nil", certName)
+		return nil, nil, re.ErrorCodeCertInvalid.NewError(re.CertProvider, providerName, re.EmptyLink, nil, "found invalid secret bundle for certificate  %s, contentType, value, and id must not be nil", re.HideStackTrace)
 	}
 
 	version := getObjectVersion(*secretBundle.ID)
@@ -232,7 +232,7 @@ func getCertsFromSecretBundle(secretBundle kv.SecretBundle, certName string) ([]
 	// akv plugin supports both PKCS12 and PEM. https://github.com/Azure/notation-azure-kv/blob/558e7345ef8318783530de6a7a0a8420b9214ba8/Notation.Plugin.AzureKeyVault/KeyVault/KeyVaultClient.cs#L192
 	if *secretBundle.ContentType != PKCS12ContentType &&
 		*secretBundle.ContentType != PEMContentType {
-		return nil, nil, errors.Errorf("certificate %s version %s, unsupported secret content type %s, supported type are %s and %s", certName, version, *secretBundle.ContentType, PKCS12ContentType, PEMContentType)
+		return nil, nil, re.ErrorCodeCertInvalid.NewError(re.CertProvider, providerName, re.EmptyLink, nil, fmt.Sprintf("certificate %s version %s, unsupported secret content type %s, supported type are %s and %s", certName, version, *secretBundle.ContentType, PKCS12ContentType, PEMContentType), re.HideStackTrace)
 	}
 
 	results := []*x509.Certificate{}
@@ -244,12 +244,12 @@ func getCertsFromSecretBundle(secretBundle kv.SecretBundle, certName string) ([]
 	if *secretBundle.ContentType == PKCS12ContentType {
 		p12, err := base64.StdEncoding.DecodeString(*secretBundle.Value)
 		if err != nil {
-			return nil, nil, fmt.Errorf("azure keyvault certificate provider: failed to decode PKCS12 Value. Certificate %s, version %s, error: %w", certName, version, err)
+			return nil, nil, re.ErrorCodeCertInvalid.NewError(re.CertProvider, providerName, re.EmptyLink, err, fmt.Sprintf("azure keyvault certificate provider: failed to decode PKCS12 Value. Certificate %s, version %s", certName, version), re.HideStackTrace)
 		}
 
 		blocks, err := pkcs12.ToPEM(p12, "")
 		if err != nil {
-			return nil, nil, fmt.Errorf("azure keyvault certificate provider: failed to convert PKCS12 Value to PEM. Certificate %s, version %s, error: %w", certName, version, err)
+			return nil, nil, re.ErrorCodeCertInvalid.NewError(re.CertProvider, providerName, re.EmptyLink, err, fmt.Sprintf("azure keyvault certificate provider: failed to convert PKCS12 Value to PEM. Certificate %s, version %s", certName, version), re.HideStackTrace)
 		}
 
 		var pemData []byte
@@ -270,7 +270,7 @@ func getCertsFromSecretBundle(secretBundle kv.SecretBundle, certName string) ([]
 			pemData = append(pemData, pem.EncodeToMemory(block)...)
 			decodedCerts, err := certificateprovider.DecodeCertificates(pemData)
 			if err != nil {
-				return nil, nil, fmt.Errorf("azure keyvault certificate provider: failed to decode Certificate %s, version %s, error: %w", certName, version, err)
+				return nil, nil, re.ErrorCodeCertInvalid.NewError(re.CertProvider, providerName, re.EmptyLink, err, fmt.Sprintf("azure keyvault certificate provider: failed to decode Certificate %s, version %s", certName, version), re.HideStackTrace)
 			}
 			for _, cert := range decodedCerts {
 				results = append(results, cert)
@@ -283,7 +283,7 @@ func getCertsFromSecretBundle(secretBundle kv.SecretBundle, certName string) ([]
 
 		block, rest = pem.Decode(rest)
 		if block == nil && len(rest) > 0 {
-			return nil, nil, errors.Errorf("certificate '%s', version '%s': azure keyvault certificate provider error, block is nil and remaining block to parse > 0", certName, version)
+			return nil, nil, re.ErrorCodeCertInvalid.NewError(re.CertProvider, providerName, re.EmptyLink, nil, fmt.Sprintf("certificate '%s', version '%s': azure keyvault certificate provider error, block is nil and remaining block to parse > 0", certName, version), re.HideStackTrace)
 		}
 	}
 	logrus.Debugf("azurekeyvault certprovider getCertsFromSecretBundle: %v certificates parsed, Certificate '%s', version '%s'", len(results), certName, version)
diff --git a/pkg/certificateprovider/certificate_provider.go b/pkg/certificateprovider/certificate_provider.go
index 1327932..80f7f06 100644
--- a/pkg/certificateprovider/certificate_provider.go
+++ b/pkg/certificateprovider/certificate_provider.go
@@ -20,6 +20,8 @@ import (
 	"crypto/x509"
 	"encoding/pem"
 	"fmt"
+
+	"github.com/deislabs/ratify/errors"
 )
 
 // This is a map containing Cert store configuration including name, tenantID, and cert object information
@@ -56,20 +58,20 @@ func DecodeCertificates(value []byte) ([]*x509.Certificate, error) {
 	var certs []*x509.Certificate
 	block, rest := pem.Decode(value)
 	if block == nil && len(rest) > 0 {
-		return nil, fmt.Errorf("failed to decode pem block")
+		return nil, errors.ErrorCodeCertInvalid.WithComponentType(errors.CertProvider).WithDetail("failed to decode pem block")
 	}
 
 	for block != nil {
 		if block.Type == "CERTIFICATE" {
 			cert, err := x509.ParseCertificate(block.Bytes)
 			if err != nil {
-				return nil, fmt.Errorf("error parsing x509 certificate: %w", err)
+				return nil, errors.ErrorCodeCertInvalid.WithComponentType(errors.CertProvider).WithDetail("error parsing x509 certificate")
 			}
 			certs = append(certs, cert)
 		}
 		block, rest = pem.Decode(rest)
 		if block == nil && len(rest) > 0 {
-			return nil, fmt.Errorf("failed to decode pem block")
+			return nil, errors.ErrorCodeCertInvalid.WithComponentType(errors.CertProvider).WithDetail("failed to decode pem block")
 		}
 	}
 
diff --git a/pkg/certificateprovider/inline/provider.go b/pkg/certificateprovider/inline/provider.go
index d21f278..d52a07e 100644
--- a/pkg/certificateprovider/inline/provider.go
+++ b/pkg/certificateprovider/inline/provider.go
@@ -18,8 +18,8 @@ package inline
 import (
 	"context"
 	"crypto/x509"
-	"fmt"
 
+	"github.com/deislabs/ratify/errors"
 	"github.com/deislabs/ratify/pkg/certificateprovider"
 )
 
@@ -45,10 +45,12 @@ func Create() certificateprovider.CertificateProvider {
 func (s *inlineCertProvider) GetCertificates(_ context.Context, attrib map[string]string) ([]*x509.Certificate, certificateprovider.CertificatesStatus, error) {
 	value, ok := attrib[ValueParameter]
 	if !ok {
-		return nil, nil, fmt.Errorf("value parameter is not set")
+		return nil, nil, errors.ErrorCodeConfigInvalid.WithDetail("value parameter is not set").WithComponentType(errors.CertProvider)
 	}
 
 	certs, err := certificateprovider.DecodeCertificates([]byte(value))
-
-	return certs, nil, err
+	if err != nil {
+		return nil, nil, errors.ErrorCodeCertInvalid.WithComponentType(errors.CertProvider)
+	}
+	return certs, nil, nil
 }
diff --git a/pkg/common/oras/authprovider/authprovider.go b/pkg/common/oras/authprovider/authprovider.go
index e45d73e..1acd27b 100644
--- a/pkg/common/oras/authprovider/authprovider.go
+++ b/pkg/common/oras/authprovider/authprovider.go
@@ -19,12 +19,12 @@ import (
 	"context"
 	"encoding/json"
 	"errors"
-	"fmt"
 	"net/url"
 	"os"
 	"strings"
 	"time"
 
+	re "github.com/deislabs/ratify/errors"
 	"github.com/docker/cli/cli/config"
 	"github.com/docker/cli/cli/config/configfile"
 )
@@ -76,11 +76,11 @@ func (s *defaultProviderFactory) Create(authProviderConfig AuthProviderConfig) (
 	conf := defaultAuthProviderConf{}
 	authProviderConfigBytes, err := json.Marshal(authProviderConfig)
 	if err != nil {
-		return nil, err
+		return nil, re.ErrorCodeConfigInvalid.WithError(err).WithComponentType(re.AuthProvider)
 	}
 
 	if err := json.Unmarshal(authProviderConfigBytes, &conf); err != nil {
-		return nil, fmt.Errorf("failed to parse auth provider configuration: %w", err)
+		return nil, re.ErrorCodeConfigInvalid.NewError(re.AuthProvider, "", re.AuthProviderLink, err, "failed to parse auth provider configuration", re.HideStackTrace)
 	}
 
 	return &defaultAuthProvider{
@@ -100,26 +100,26 @@ func (d *defaultAuthProvider) Provide(_ context.Context, artifact string) (AuthC
 	if d.configPath == "" {
 		var err error
 		if cfg, err = config.Load(config.Dir()); err != nil {
-			return AuthConfig{}, err
+			return AuthConfig{}, re.ErrorCodeConfigInvalid.WithError(err).WithComponentType(re.AuthProvider)
 		}
 	} else {
 		cfg = configfile.New(d.configPath)
 		if _, err := os.Stat(d.configPath); err != nil {
-			return AuthConfig{}, err
+			return AuthConfig{}, re.ErrorCodeConfigInvalid.WithError(err).WithComponentType(re.AuthProvider)
 		}
 		file, err := os.Open(d.configPath)
 		if err != nil {
-			return AuthConfig{}, err
+			return AuthConfig{}, re.ErrorCodeConfigInvalid.WithError(err).WithComponentType(re.AuthProvider)
 		}
 		defer file.Close()
 		if err := cfg.LoadFromReader(file); err != nil {
-			return AuthConfig{}, err
+			return AuthConfig{}, re.ErrorCodeConfigInvalid.WithError(err).WithComponentType(re.AuthProvider)
 		}
 	}
 
 	artifactHostName, err := GetRegistryHostName(artifact)
 	if err != nil {
-		return AuthConfig{}, err
+		return AuthConfig{}, re.ErrorCodeHostNameInvalid.WithError(err).WithComponentType(re.AuthProvider)
 	}
 
 	dockerAuthConfig := cfg.AuthConfigs[artifactHostName]
diff --git a/pkg/common/oras/authprovider/authproviderfactory.go b/pkg/common/oras/authprovider/authproviderfactory.go
index 05a00c1..4536b83 100644
--- a/pkg/common/oras/authprovider/authproviderfactory.go
+++ b/pkg/common/oras/authprovider/authproviderfactory.go
@@ -18,6 +18,7 @@ package authprovider
 import (
 	"fmt"
 
+	"github.com/deislabs/ratify/errors"
 	"github.com/sirupsen/logrus"
 )
 
@@ -52,23 +53,23 @@ func CreateAuthProviderFromConfig(authProviderConfig AuthProviderConfig) (AuthPr
 
 	err := validateAuthProviderConfig(authProviderConfig)
 	if err != nil {
-		return nil, err
+		return nil, errors.ErrorCodeAuthDenied.WithError(err).WithComponentType(errors.AuthProvider)
 	}
 
 	authProviderName, ok := authProviderConfig["name"]
 	if !ok {
-		return nil, fmt.Errorf("failed to find auth provider name in the auth providers config with key %s", "name")
+		return nil, errors.ErrorCodeAuthDenied.WithDetail(fmt.Sprintf("failed to find auth provider name in the auth providers config with key %s", "name")).WithComponentType(errors.AuthProvider)
 	}
 
 	providerNameStr := fmt.Sprintf("%s", authProviderName)
 
 	authFactory, ok := builtInAuthProviders[providerNameStr]
 	if !ok {
-		return nil, fmt.Errorf("failed to find auth provider implementation with name %s", providerNameStr)
+		return nil, errors.ErrorCodeAuthDenied.WithDetail(fmt.Sprintf("failed to find auth provider implementation with name %s", providerNameStr)).WithComponentType(errors.AuthProvider)
 	}
 	authProvider, err := authFactory.Create(authProviderConfig)
 	if err != nil {
-		return nil, err
+		return nil, errors.ErrorCodeAuthDenied.WithError(err).WithComponentType(errors.AuthProvider)
 	}
 
 	logrus.Infof("selected auth provider: %s", providerNameStr)
diff --git a/pkg/common/oras/authprovider/azure/azureidentity.go b/pkg/common/oras/authprovider/azure/azureidentity.go
index 5eed625..7983fbc 100644
--- a/pkg/common/oras/authprovider/azure/azureidentity.go
+++ b/pkg/common/oras/authprovider/azure/azureidentity.go
@@ -22,8 +22,8 @@ import (
 	"os"
 	"time"
 
+	re "github.com/deislabs/ratify/errors"
 	provider "github.com/deislabs/ratify/pkg/common/oras/authprovider"
-	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 
 	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
@@ -44,13 +44,6 @@ type azureManagedIdentityAuthProviderConf struct {
 	ClientID string `json:"clientID"`
 }
 
-var (
-	// ErrorNoAuth indicates that no credentials are provided.
-	ErrorNoAuth    = fmt.Errorf("no credentials provided for Azure cloud provider")
-	ErrorNilEnv    = fmt.Errorf("env is nil pointer for GetServicePrincipalToken")
-	ErrorNilConfig = fmt.Errorf("config is nil pointer for GetServicePrincipalToken")
-)
-
 const (
 	azureManagedIdentityAuthProviderName string = "azureManagedIdentity"
 )
@@ -65,22 +58,22 @@ func (s *azureManagedIdentityProviderFactory) Create(authProviderConfig provider
 	conf := azureManagedIdentityAuthProviderConf{}
 	authProviderConfigBytes, err := json.Marshal(authProviderConfig)
 	if err != nil {
-		return nil, err
+		return nil, re.ErrorCodeConfigInvalid.WithError(err).WithComponentType(re.AuthProvider)
 	}
 
 	if err := json.Unmarshal(authProviderConfigBytes, &conf); err != nil {
-		return nil, fmt.Errorf("failed to parse azure managed identity auth provider configuration: %w", err)
+		return nil, re.ErrorCodeConfigInvalid.NewError(re.AuthProvider, "", re.AzureManagedIdentityLink, err, "failed to parse azure managed identity auth provider configuration.", re.HideStackTrace)
 	}
 
 	tenant := os.Getenv("AZURE_TENANT_ID")
 	if tenant == "" {
-		return nil, fmt.Errorf("AZURE_TENANT_ID environment variable is empty")
+		return nil, re.ErrorCodeEnvNotSet.WithDetail("AZURE_TENANT_ID environment variable is empty").WithComponentType(re.AuthProvider)
 	}
 	client := os.Getenv("AZURE_CLIENT_ID")
 	if client == "" {
 		client = conf.ClientID
 		if client == "" {
-			return nil, fmt.Errorf("AZURE_CLIENT_ID environment variable is empty")
+			return nil, re.ErrorCodeEnvNotSet.WithDetail("AZURE_CLIENT_ID environment variable is empty").WithComponentType(re.AuthProvider)
 		}
 	}
 	if err != nil {
@@ -89,7 +82,7 @@ func (s *azureManagedIdentityProviderFactory) Create(authProviderConfig provider
 	// retrieve an AAD Access token
 	token, err := getManagedIdentityToken(context.Background(), client)
 	if err != nil {
-		return nil, err
+		return nil, re.ErrorCodeAuthDenied.NewError(re.AuthProvider, "", re.AzureManagedIdentityLink, err, "", re.HideStackTrace)
 	}
 
 	return &azureManagedIdentityAuthProvider{
@@ -133,7 +126,7 @@ func (d *azureManagedIdentityAuthProvider) Provide(ctx context.Context, artifact
 	if time.Now().Add(time.Minute * 5).After(d.identityToken.ExpiresOn) {
 		newToken, err := getManagedIdentityToken(ctx, d.clientID)
 		if err != nil {
-			return provider.AuthConfig{}, errors.Wrap(err, "could not refresh azure managed identity token")
+			return provider.AuthConfig{}, re.ErrorCodeAuthDenied.NewError(re.AuthProvider, "", re.AzureManagedIdentityLink, err, "could not refresh azure managed identity token", re.HideStackTrace)
 		}
 		d.identityToken = newToken
 		logrus.Info("successfully refreshed azure managed identity token")
@@ -145,7 +138,7 @@ func (d *azureManagedIdentityAuthProvider) Provide(ctx context.Context, artifact
 	refreshTokenClient := containerregistry.NewRefreshTokensClient(serverURL)
 	rt, err := refreshTokenClient.GetFromExchange(ctx, "access_token", artifactHostName, d.tenantID, "", d.identityToken.Token)
 	if err != nil {
-		return provider.AuthConfig{}, fmt.Errorf("failed to get refresh token for container registry by azure managed identity token - %w", err)
+		return provider.AuthConfig{}, re.ErrorCodeAuthDenied.NewError(re.AuthProvider, "", re.AzureManagedIdentityLink, err, "failed to get refresh token for container registry by azure managed identity token", re.HideStackTrace)
 	}
 
 	expiresOn := getACRExpiryIfEarlier(d.identityToken.ExpiresOn)
@@ -171,5 +164,5 @@ func getManagedIdentityToken(ctx context.Context, clientID string) (azcore.Acces
 	if cred != nil {
 		return cred.GetToken(ctx, policy.TokenRequestOptions{Scopes: scopes})
 	}
-	return azcore.AccessToken{}, ErrorNilConfig
+	return azcore.AccessToken{}, re.ErrorCodeConfigInvalid.WithComponentType(re.AuthProvider).WithDetail("config is nil pointer for GetServicePrincipalToken")
 }
diff --git a/pkg/common/oras/authprovider/azure/azureworkloadidentity.go b/pkg/common/oras/authprovider/azure/azureworkloadidentity.go
index c83e0e9..008470d 100644
--- a/pkg/common/oras/authprovider/azure/azureworkloadidentity.go
+++ b/pkg/common/oras/authprovider/azure/azureworkloadidentity.go
@@ -18,17 +18,16 @@ package azure
 import (
 	"context"
 	"encoding/json"
-	"fmt"
 	"os"
 	"time"
 
+	re "github.com/deislabs/ratify/errors"
 	provider "github.com/deislabs/ratify/pkg/common/oras/authprovider"
 	"github.com/deislabs/ratify/pkg/metrics"
 	"github.com/deislabs/ratify/pkg/utils/azureauth"
 
 	"github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/runtime/2019-08-15-preview/containerregistry"
 	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential"
-	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 )
 
@@ -58,30 +57,30 @@ func (s *AzureWIProviderFactory) Create(authProviderConfig provider.AuthProvider
 	conf := azureWIAuthProviderConf{}
 	authProviderConfigBytes, err := json.Marshal(authProviderConfig)
 	if err != nil {
-		return nil, err
+		return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.AuthProvider).WithError(err)
 	}
 
 	if err := json.Unmarshal(authProviderConfigBytes, &conf); err != nil {
-		return nil, fmt.Errorf("failed to parse auth provider configuration: %w", err)
+		return nil, re.ErrorCodeConfigInvalid.NewError(re.AuthProvider, "", re.EmptyLink, err, "failed to parse auth provider configuration", re.HideStackTrace)
 	}
 
 	tenant := os.Getenv("AZURE_TENANT_ID")
 
 	if tenant == "" {
-		return nil, fmt.Errorf("azure tenant id environment variable is empty")
+		return nil, re.ErrorCodeEnvNotSet.WithComponentType(re.AuthProvider).WithDetail("azure tenant id environment variable is empty")
 	}
 	clientID := conf.ClientID
 	if clientID == "" {
 		clientID = os.Getenv("AZURE_CLIENT_ID")
 		if clientID == "" {
-			return nil, fmt.Errorf("no client ID provided and AZURE_CLIENT_ID environment variable is empty")
+			return nil, re.ErrorCodeEnvNotSet.WithComponentType(re.AuthProvider).WithDetail("no client ID provided and AZURE_CLIENT_ID environment variable is empty")
 		}
 	}
 
 	// retrieve an AAD Access token
 	token, err := azureauth.GetAADAccessToken(context.Background(), tenant, clientID, AADResource)
 	if err != nil {
-		return nil, err
+		return nil, re.ErrorCodeAuthDenied.NewError(re.AuthProvider, "", re.AzureWorkloadIdentityLink, err, "", re.HideStackTrace)
 	}
 
 	return &azureWIAuthProvider{
@@ -109,19 +108,19 @@ func (d *azureWIAuthProvider) Enabled(_ context.Context) bool {
 // exchanged for a valid ACR refresh token for login.
 func (d *azureWIAuthProvider) Provide(ctx context.Context, artifact string) (provider.AuthConfig, error) {
 	if !d.Enabled(ctx) {
-		return provider.AuthConfig{}, fmt.Errorf("azure workload identity auth provider is not properly enabled")
+		return provider.AuthConfig{}, re.ErrorCodeConfigInvalid.WithComponentType(re.AuthProvider).WithDetail("azure workload identity auth provider is not properly enabled")
 	}
 	// parse the artifact reference string to extract the registry host name
 	artifactHostName, err := provider.GetRegistryHostName(artifact)
 	if err != nil {
-		return provider.AuthConfig{}, err
+		return provider.AuthConfig{}, re.ErrorCodeHostNameInvalid.WithComponentType(re.AuthProvider)
 	}
 
 	// need to refresh AAD token if it's expired
 	if time.Now().Add(time.Minute * 5).After(d.aadToken.ExpiresOn) {
 		newToken, err := azureauth.GetAADAccessToken(ctx, d.tenantID, d.clientID, AADResource)
 		if err != nil {
-			return provider.AuthConfig{}, errors.Wrap(err, "could not refresh AAD token")
+			return provider.AuthConfig{}, re.ErrorCodeAuthDenied.NewError(re.AuthProvider, "", re.AzureWorkloadIdentityLink, nil, "could not refresh AAD token", re.HideStackTrace)
 		}
 		d.aadToken = newToken
 		logrus.Info("successfully refreshed AAD token")
@@ -135,7 +134,7 @@ func (d *azureWIAuthProvider) Provide(ctx context.Context, artifact string) (pro
 	startTime := time.Now()
 	rt, err := refreshTokenClient.GetFromExchange(context.Background(), "access_token", artifactHostName, d.tenantID, "", d.aadToken.AccessToken)
 	if err != nil {
-		return provider.AuthConfig{}, fmt.Errorf("failed to get refresh token for container registry - %w", err)
+		return provider.AuthConfig{}, re.ErrorCodeAuthDenied.NewError(re.AuthProvider, "", re.AzureWorkloadIdentityLink, err, "failed to get refresh token for container registry", re.HideStackTrace)
 	}
 	metrics.ReportACRExchangeDuration(ctx, time.Since(startTime).Milliseconds(), artifactHostName)
 
diff --git a/pkg/common/oras/authprovider/k8secret_authprovider.go b/pkg/common/oras/authprovider/k8secret_authprovider.go
index 006ed1c..7d15fbe 100644
--- a/pkg/common/oras/authprovider/k8secret_authprovider.go
+++ b/pkg/common/oras/authprovider/k8secret_authprovider.go
@@ -24,6 +24,7 @@ import (
 	"os"
 	"time"
 
+	re "github.com/deislabs/ratify/errors"
 	"github.com/docker/cli/cli/config"
 	core "k8s.io/api/core/v1"
 	meta "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -53,8 +54,6 @@ const defaultName = "default"
 const ratifyNamespaceEnv = "RATIFY_NAMESPACE"
 const secretTimeout = time.Hour * 12
 
-var ErrorNoMatchingCredential = errors.New("no matching credential found for k8 secret")
-
 // init calls Register for our k8Secrets provider
 func init() {
 	Register("k8Secrets", &k8SecretProviderFactory{})
@@ -66,21 +65,21 @@ func (s *k8SecretProviderFactory) Create(authProviderConfig AuthProviderConfig)
 	conf := k8SecretAuthProviderConf{}
 	authProviderConfigBytes, err := json.Marshal(authProviderConfig)
 	if err != nil {
-		return nil, fmt.Errorf("failed to marshal authentication provider config: %w", err)
+		return nil, re.ErrorCodeConfigInvalid.NewError(re.AuthProvider, "", re.EmptyLink, err, "failed to marshal authentication provider config", re.HideStackTrace)
 	}
 
 	if err := json.Unmarshal(authProviderConfigBytes, &conf); err != nil {
-		return nil, fmt.Errorf("failed to parse authentication provider configuration: %w", err)
+		return nil, re.ErrorCodeConfigInvalid.NewError(re.AuthProvider, "", re.EmptyLink, err, "failed to parse authentication provider configuration", re.HideStackTrace)
 	}
 
 	clusterConfig, err := rest.InClusterConfig()
 	if err != nil {
-		return nil, fmt.Errorf("failed to generate cluster configuration: %w", err)
+		return nil, re.ErrorCodeConfigInvalid.NewError(re.AuthProvider, "", re.EmptyLink, err, "failed to generate cluster configuration", re.HideStackTrace)
 	}
 
 	clientSet, err := kubernetes.NewForConfig(clusterConfig)
 	if err != nil {
-		return nil, fmt.Errorf("failed to create kubernetes client set from config: %w", err)
+		return nil, re.ErrorCodeConfigInvalid.NewError(re.AuthProvider, "", re.EmptyLink, err, "failed to create kubernetes client set from config", re.HideStackTrace)
 	}
 
 	if conf.ServiceAccountName == "" {
@@ -90,7 +89,7 @@ func (s *k8SecretProviderFactory) Create(authProviderConfig AuthProviderConfig)
 	// get name of namespace ratify is running in
 	namespace := os.Getenv(ratifyNamespaceEnv)
 	if namespace == "" {
-		return nil, fmt.Errorf("environment variable %s not set", ratifyNamespaceEnv)
+		return nil, re.ErrorCodeEnvNotSet.WithComponentType(re.AuthProvider).WithDetail(fmt.Sprintf("environment variable %s not set", ratifyNamespaceEnv))
 	}
 
 	return &k8SecretAuthProvider{
@@ -118,7 +117,7 @@ func (d *k8SecretAuthProvider) Provide(ctx context.Context, artifact string) (Au
 
 	hostName, err := GetRegistryHostName(artifact)
 	if err != nil {
-		return AuthConfig{}, err
+		return AuthConfig{}, re.ErrorCodeHostNameInvalid.WithError(err).WithComponentType(re.AuthProvider)
 	}
 
 	// iterate through config secrets, resolve each secret, and store in map
@@ -130,13 +129,13 @@ func (d *k8SecretAuthProvider) Provide(ctx context.Context, artifact string) (Au
 
 		secret, err := d.clusterClientSet.CoreV1().Secrets(k8secret.Namespace).Get(ctx, k8secret.SecretName, meta.GetOptions{})
 		if err != nil {
-			return AuthConfig{}, fmt.Errorf("failed to pull secret %s from cluster: %w", k8secret.SecretName, err)
+			return AuthConfig{}, re.ErrorCodeGetClusterResourceFailure.NewError(re.AuthProvider, "", re.EmptyLink, err, fmt.Sprintf("failed to pull secret %s from cluster.", k8secret.SecretName), re.HideStackTrace)
 		}
 
 		// only docker config json secret type allowed
 		if secret.Type == core.SecretTypeDockerConfigJson {
 			authConfig, err := d.resolveCredentialFromSecret(hostName, secret)
-			if err != nil && !errors.Is(err, ErrorNoMatchingCredential) {
+			if err != nil && !errors.Is(err, re.ErrorCodeNoMatchingCredential) {
 				return AuthConfig{}, err
 			}
 			// if a resolved AuthConfig is returned
@@ -151,20 +150,20 @@ func (d *k8SecretAuthProvider) Provide(ctx context.Context, artifact string) (Au
 	// get the the service account for ratify
 	serviceAccount, err := d.clusterClientSet.CoreV1().ServiceAccounts(d.ratifyNamespace).Get(ctx, d.config.ServiceAccountName, meta.GetOptions{})
 	if err != nil {
-		return AuthConfig{}, err
+		return AuthConfig{}, re.ErrorCodeGetClusterResourceFailure.WithError(err).WithComponentType(re.AuthProvider)
 	}
 
 	// extract the imagePullSecrets linked to service account
 	for _, imagePullSecret := range serviceAccount.ImagePullSecrets {
 		secret, err := d.clusterClientSet.CoreV1().Secrets(d.ratifyNamespace).Get(ctx, imagePullSecret.Name, meta.GetOptions{})
 		if err != nil {
-			return AuthConfig{}, err
+			return AuthConfig{}, re.ErrorCodeGetClusterResourceFailure.WithError(err).WithComponentType(re.AuthProvider)
 		}
 
 		// only dockercfg or docker config json secret type allowed
 		if secret.Type == core.SecretTypeDockercfg || secret.Type == core.SecretTypeDockerConfigJson {
 			authConfig, err := d.resolveCredentialFromSecret(hostName, secret)
-			if err != nil && !errors.Is(err, ErrorNoMatchingCredential) {
+			if err != nil && !errors.Is(err, re.ErrorCodeNoMatchingCredential) {
 				return AuthConfig{}, err
 			}
 			// if a resolved AuthConfig is returned
@@ -180,17 +179,17 @@ func (d *k8SecretAuthProvider) Provide(ctx context.Context, artifact string) (Au
 func (d *k8SecretAuthProvider) resolveCredentialFromSecret(hostName string, secret *core.Secret) (AuthConfig, error) {
 	dockercfg, exists := secret.Data[core.DockerConfigJsonKey]
 	if !exists {
-		return AuthConfig{}, fmt.Errorf("could not extract auth configs from docker config")
+		return AuthConfig{}, re.ErrorCodeConfigInvalid.WithDetail("could not extract auth configs from docker config")
 	}
 
 	configFile, err := config.LoadFromReader(bytes.NewReader(dockercfg))
 	if err != nil {
-		return AuthConfig{}, err
+		return AuthConfig{}, re.ErrorCodeConfigInvalid.WithError(err).WithComponentType(re.AuthProvider)
 	}
 
 	authConfig, exist := configFile.AuthConfigs[hostName]
 	if !exist {
-		return AuthConfig{}, ErrorNoMatchingCredential
+		return AuthConfig{}, re.ErrorCodeNoMatchingCredential
 	}
 
 	return AuthConfig{
diff --git a/pkg/executor/core/executor.go b/pkg/executor/core/executor.go
index be6e9ce..02a75a0 100644
--- a/pkg/executor/core/executor.go
+++ b/pkg/executor/core/executor.go
@@ -21,6 +21,7 @@ import (
 	"sync"
 	"time"
 
+	"github.com/deislabs/ratify/errors"
 	"github.com/deislabs/ratify/pkg/common"
 	e "github.com/deislabs/ratify/pkg/executor"
 	"github.com/deislabs/ratify/pkg/executor/config"
@@ -75,7 +76,7 @@ func (executor Executor) verifySubjectInternal(ctx context.Context, verifyParame
 	}
 	if executor.PolicyEnforcer.GetPolicyType(ctx) == pt.ConfigPolicy {
 		if len(verifierReports) == 0 {
-			return types.VerifyResult{}, ErrReferrersNotFound
+			return types.VerifyResult{}, errors.ErrorCodeReferrersNotFound.WithComponentType(errors.Executor)
 		}
 	}
 	// If it requires embedded Rego Policy Engine make the decision, execute
@@ -95,9 +96,8 @@ func (executor Executor) verifySubjectInternalWithoutDecision(ctx context.Contex
 	}
 
 	desc, err := su.ResolveSubjectDescriptor(ctx, &executor.ReferrerStores, subjectReference)
-
 	if err != nil {
-		return nil, fmt.Errorf("resolving descriptor for the subject failed with error: %w", err)
+		return nil, err
 	}
 
 	logrus.Infof("Resolve of the image completed successfully the digest is %s", desc.Digest)
@@ -116,7 +116,7 @@ func (executor Executor) verifySubjectInternalWithoutDecision(ctx context.Contex
 			for {
 				referrersResult, err := referrerStore.ListReferrers(errCtx, subjectReference, verifyParameters.ReferenceTypes, continuationToken, desc)
 				if err != nil {
-					return err
+					return errors.ErrorCodeListReferrersFailure.NewError(errors.ReferrerStore, referrerStore.Name(), errors.EmptyLink, err, nil, errors.HideStackTrace)
 				}
 				continuationToken = referrersResult.NextToken
 				for _, reference := range referrersResult.Referrers {
@@ -173,7 +173,7 @@ func (executor Executor) verifyReferenceForJSONPolicy(ctx context.Context, subje
 				verifyResult = vr.VerifierResult{
 					IsSuccess: false,
 					Name:      verifier.Name(),
-					Message:   fmt.Sprintf("an error thrown by the verifier: %v", err)}
+					Message:   errors.ErrorCodeVerifyReferenceFailure.NewError(errors.Verifier, verifier.Name(), errors.EmptyLink, err, nil, errors.HideStackTrace).Error()}
 			}
 
 			if len(verifier.GetNestedReferences()) > 0 {
@@ -221,7 +221,7 @@ func (executor Executor) verifyReferenceForRegoPolicy(ctx context.Context, subje
 				verifierReport = vt.VerifierResult{
 					IsSuccess: false,
 					Name:      verifier.Name(),
-					Message:   fmt.Sprintf("an error thrown by the verifier: %v", err)}
+					Message:   errors.ErrorCodeVerifyReferenceFailure.NewError(errors.Verifier, verifier.Name(), errors.EmptyLink, err, nil, errors.HideStackTrace).Error()}
 			} else {
 				verifierReport = vt.NewVerifierResult(verifierResult)
 			}
@@ -284,7 +284,7 @@ func (executor Executor) addNestedReports(ctx context.Context, referenceDes ocis
 	for _, report := range reports.VerifierReports {
 		nestedReport, err := types.NewNestedVerifierReport(report)
 		if err != nil {
-			return err
+			return errors.ErrorCodeExecutorFailure.WithError(err).WithComponentType(errors.Executor)
 		}
 		nestedReports = append(nestedReports, nestedReport)
 	}
diff --git a/pkg/policyprovider/configpolicy/configpolicy.go b/pkg/policyprovider/configpolicy/configpolicy.go
index 62685d7..d8bfcf5 100644
--- a/pkg/policyprovider/configpolicy/configpolicy.go
+++ b/pkg/policyprovider/configpolicy/configpolicy.go
@@ -20,6 +20,7 @@ import (
 	"encoding/json"
 	"fmt"
 
+	re "github.com/deislabs/ratify/errors"
 	"github.com/deislabs/ratify/pkg/common"
 	"github.com/deislabs/ratify/pkg/executor/types"
 	"github.com/deislabs/ratify/pkg/ocispecs"
@@ -58,11 +59,11 @@ func (f *configPolicyFactory) Create(policyConfig config.PolicyPluginConfig) (po
 	conf := configPolicyEnforcerConf{}
 	policyProviderConfigBytes, err := json.Marshal(policyConfig)
 	if err != nil {
-		return nil, fmt.Errorf("failed to marshal policy config: %w", err)
+		return nil, re.ErrorCodeDataEncodingFailure.NewError(re.PolicyProvider, vt.ConfigPolicy, re.PolicyProviderLink, err, "failed to marshal policy config", re.HideStackTrace)
 	}
 
 	if err := json.Unmarshal(policyProviderConfigBytes, &conf); err != nil {
-		return nil, fmt.Errorf("failed to parse policy provider configuration: %w", err)
+		return nil, re.ErrorCodeDataDecodingFailure.NewError(re.PolicyProvider, vt.ConfigPolicy, re.PolicyProviderLink, err, "failed to unmarshal policy config", re.HideStackTrace)
 	}
 
 	if conf.ArtifactVerificationPolicies == nil {
diff --git a/pkg/policyprovider/factory/factory.go b/pkg/policyprovider/factory/factory.go
index d1d5da8..d43b18b 100644
--- a/pkg/policyprovider/factory/factory.go
+++ b/pkg/policyprovider/factory/factory.go
@@ -16,10 +16,10 @@ limitations under the License.
 package factory
 
 import (
-	"errors"
 	"fmt"
 	"strings"
 
+	re "github.com/deislabs/ratify/errors"
 	"github.com/deislabs/ratify/pkg/policyprovider"
 	"github.com/deislabs/ratify/pkg/policyprovider/config"
 	"github.com/deislabs/ratify/pkg/verifier/types"
@@ -49,24 +49,24 @@ func Register(name string, factory PolicyFactory) {
 // CreatePolicyProvidersFromConfig creates a policy provider from the provided configuration
 func CreatePolicyProviderFromConfig(policyConfig config.PoliciesConfig) (policyprovider.PolicyProvider, error) {
 	if policyConfig.PolicyPlugin == nil {
-		return nil, errors.New("policy provider config must be specified")
+		return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.PolicyProvider).WithDetail("policy provider config must be specified")
 	}
 
 	policyProviderName, ok := policyConfig.PolicyPlugin[types.Name]
 	if !ok {
-		return nil, fmt.Errorf("failed to find policy provider name in the policy config with key %s", "name")
+		return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.PolicyProvider).WithDetail(fmt.Sprintf("failed to find policy provider name in the policy config with key: %s", types.Name))
 	}
 
 	providerNameStr := strings.ToLower(fmt.Sprintf("%s", policyProviderName))
 
 	policyFactory, ok := builtInPolicyProviders[providerNameStr]
 	if !ok {
-		return nil, fmt.Errorf("failed to find registered policy provider with name %s", policyProviderName)
+		return nil, re.ErrorCodePolicyProviderNotFound.NewError(re.PolicyProvider, providerNameStr, re.EmptyLink, nil, "failed to find registered policy provider", re.HideStackTrace)
 	}
 
 	policyProvider, err := policyFactory.Create(policyConfig.PolicyPlugin)
 	if err != nil {
-		return nil, fmt.Errorf("failed to Create policy provider: %w", err)
+		return nil, re.ErrorCodePluginInitFailure.NewError(re.PolicyProvider, providerNameStr, re.PolicyProviderLink, err, "failed to create policy provider", re.HideStackTrace)
 	}
 
 	logrus.Infof("selected policy provider: %s", providerNameStr)
diff --git a/pkg/policyprovider/regopolicy/regopolicy.go b/pkg/policyprovider/regopolicy/regopolicy.go
index 5fbd770..b9f7fc3 100644
--- a/pkg/policyprovider/regopolicy/regopolicy.go
+++ b/pkg/policyprovider/regopolicy/regopolicy.go
@@ -21,6 +21,7 @@ import (
 	"fmt"
 	"os"
 
+	re "github.com/deislabs/ratify/errors"
 	"github.com/deislabs/ratify/pkg/common"
 	"github.com/deislabs/ratify/pkg/executor/types"
 	"github.com/deislabs/ratify/pkg/ocispecs"
@@ -60,21 +61,21 @@ func (f *Factory) Create(policyConfig config.PolicyPluginConfig) (policyprovider
 	conf := policyEnforcerConf{}
 	policyProviderConfigBytes, err := json.Marshal(policyConfig)
 	if err != nil {
-		return nil, fmt.Errorf("failed to marshal policy config: %w", err)
+		return nil, re.ErrorCodeConfigInvalid.NewError(re.PolicyProvider, policyTypes.RegoPolicy, re.PolicyProviderLink, err, "failed to marshal policy config", re.HideStackTrace)
 	}
 
 	if err := json.Unmarshal(policyProviderConfigBytes, &conf); err != nil {
-		return nil, fmt.Errorf("failed to parse policy provider configuration: %w", err)
+		return nil, re.ErrorCodeConfigInvalid.NewError(re.PolicyProvider, policyTypes.RegoPolicy, re.EmptyLink, err, "failed to parse policy provider configuration", re.HideStackTrace)
 	}
 	if conf.Policy == "" {
 		body, err := os.ReadFile(conf.PolicyPath)
 		if err != nil {
-			return nil, fmt.Errorf("unable to read rego policy file at path: %s, err: %w", conf.PolicyPath, err)
+			return nil, re.ErrorCodeConfigInvalid.NewError(re.PolicyProvider, policyTypes.RegoPolicy, re.PolicyProviderLink, err, fmt.Sprintf("unable to read rego policy file at path: %s", conf.PolicyPath), false)
 		}
 		conf.Policy = string(body)
 	}
 	if conf.Policy == "" {
-		return nil, fmt.Errorf("policy is required for rego policy provider")
+		return nil, re.ErrorCodeConfigInvalid.NewError(re.PolicyProvider, policyTypes.RegoPolicy, re.PolicyProviderLink, nil, "policy is required for rego policy provider", re.HideStackTrace)
 	}
 
 	engine, err := policyengine.CreateEngineFromConfig(policyengine.Config{
@@ -83,7 +84,7 @@ func (f *Factory) Create(policyConfig config.PolicyPluginConfig) (policyprovider
 		Policy:        conf.Policy,
 	})
 	if err != nil {
-		return nil, fmt.Errorf("failed to create OPA engine: %w", err)
+		return nil, re.ErrorCodePluginInitFailure.NewError(re.PolicyProvider, policyTypes.RegoPolicy, re.PolicyProviderLink, err, "failed to create OPA engine", re.HideStackTrace)
 	}
 
 	policyEnforcer := &policyEnforcer{
diff --git a/pkg/referrerstore/factory/factory.go b/pkg/referrerstore/factory/factory.go
index d88f455..099632a 100644
--- a/pkg/referrerstore/factory/factory.go
+++ b/pkg/referrerstore/factory/factory.go
@@ -16,12 +16,12 @@ limitations under the License.
 package factory
 
 import (
-	"errors"
 	"fmt"
 	"os"
 	"path"
 	"strings"
 
+	re "github.com/deislabs/ratify/errors"
 	pluginCommon "github.com/deislabs/ratify/pkg/common/plugin"
 	"github.com/deislabs/ratify/pkg/featureflag"
 	"github.com/deislabs/ratify/pkg/referrerstore"
@@ -53,12 +53,12 @@ func Register(name string, factory StoreFactory) {
 func CreateStoreFromConfig(storeConfig config.StorePluginConfig, configVersion string, pluginBinDir []string) (referrerstore.ReferrerStore, error) {
 	storeName, ok := storeConfig[types.Name]
 	if !ok {
-		return nil, fmt.Errorf("failed to find store name in the stores config with key %s", "name")
+		return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.ReferrerStore).WithDetail(fmt.Sprintf("failed to find store name in the stores config with key %s", types.Name))
 	}
 
 	storeNameStr := fmt.Sprintf("%s", storeName)
 	if strings.ContainsRune(storeNameStr, os.PathSeparator) {
-		return nil, fmt.Errorf("invalid plugin name for a store: %s", storeName)
+		return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.ReferrerStore).WithDetail(fmt.Sprintf("invalid plugin name for a store: %s", storeName))
 	}
 
 	// if source is specified, download the plugin
@@ -66,13 +66,13 @@ func CreateStoreFromConfig(storeConfig config.StorePluginConfig, configVersion s
 		if featureflag.DynamicPlugins.Enabled {
 			source, err := pluginCommon.ParsePluginSource(source)
 			if err != nil {
-				return nil, fmt.Errorf("failed to parse plugin source: %w", err)
+				return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.ReferrerStore).WithDetail("failed to parse plugin source")
 			}
 
 			targetPath := path.Join(pluginBinDir[0], storeNameStr)
 			err = pluginCommon.DownloadPlugin(source, targetPath)
 			if err != nil {
-				return nil, fmt.Errorf("failed to download plugin: %w", err)
+				return nil, re.ErrorCodeDownloadPluginFailure.WithComponentType(re.ReferrerStore)
 			}
 			logrus.Infof("downloaded store plugin %s from %s to %s", storeNameStr, source.Artifact, targetPath)
 		} else {
@@ -95,11 +95,11 @@ func CreateStoresFromConfig(storesConfig config.StoresConfig, defaultPluginPath
 
 	err := validateStoresConfig(&storesConfig)
 	if err != nil {
-		return nil, err
+		return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.ReferrerStore).WithError(err)
 	}
 
 	if len(storesConfig.Stores) == 0 {
-		return nil, errors.New("referrer store config should have at least one store")
+		return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.ReferrerStore).WithDetail("referrer store config should have at least one store")
 	}
 
 	stores := make([]referrerstore.ReferrerStore, 0)
diff --git a/pkg/referrerstore/oras/cache.go b/pkg/referrerstore/oras/cache.go
index 51bf5b0..c2699cc 100644
--- a/pkg/referrerstore/oras/cache.go
+++ b/pkg/referrerstore/oras/cache.go
@@ -21,6 +21,7 @@ import (
 	"fmt"
 	"time"
 
+	"github.com/deislabs/ratify/errors"
 	"github.com/deislabs/ratify/pkg/cache"
 	"github.com/deislabs/ratify/pkg/common"
 	"github.com/deislabs/ratify/pkg/ocispecs"
@@ -61,7 +62,7 @@ func (store *orasStoreWithInMemoryCache) ListReferrers(ctx context.Context, subj
 		val, found := cacheProvider.Get(ctx, cacheKey)
 		if val != "" && found {
 			if err = json.Unmarshal([]byte(val), &result); err != nil {
-				logrus.Warningf("failed to unmarshal cache value for key %+v: %v", cacheKey, err)
+				logrus.Warning(errors.ErrorCodeDataDecodingFailure.NewError(errors.Cache, "", errors.EmptyLink, err, fmt.Sprintf("failed to unmarshal cache value for key %s: %s", cacheKey, val), errors.HideStackTrace))
 			} else {
 				logrus.Debug("cache hit for list referrers")
 				return result, nil
@@ -91,7 +92,7 @@ func (store *orasStoreWithInMemoryCache) GetSubjectDescriptor(ctx context.Contex
 		val, found := cacheProvider.Get(ctx, fmt.Sprintf(cache.CacheKeySubjectDescriptor, subjectReference.Digest))
 		if val != "" && found {
 			if err = json.Unmarshal([]byte(val), result); err != nil {
-				logrus.Warningf("failed to unmarshal cache value: %v", err)
+				logrus.Warning(errors.ErrorCodeDataDecodingFailure.NewError(errors.Cache, "", errors.EmptyLink, err, fmt.Sprintf("failed to unmarshal cache value: %v", val), errors.HideStackTrace))
 			} else {
 				logrus.Debug("cache hit for subject descriptor")
 				return result, nil
diff --git a/pkg/referrerstore/oras/cosign.go b/pkg/referrerstore/oras/cosign.go
index dd8ac61..7d0d9a7 100644
--- a/pkg/referrerstore/oras/cosign.go
+++ b/pkg/referrerstore/oras/cosign.go
@@ -21,6 +21,7 @@ import (
 	"fmt"
 	"strings"
 
+	re "github.com/deislabs/ratify/errors"
 	"github.com/deislabs/ratify/pkg/common"
 	"github.com/deislabs/ratify/pkg/ocispecs"
 	oci "github.com/opencontainers/image-spec/specs-go/v1"
@@ -32,8 +33,6 @@ import (
 const CosignArtifactType = "application/vnd.dev.cosign.artifact.sig.v1+json"
 const CosignSignatureTagSuffix = ".sig"
 
-var ErrNoCosignSubjectDigest = errors.New("failed to mutate cosign image tag: no digest specified for subject")
-
 func getCosignReferences(ctx context.Context, subjectReference common.Reference, repository registry.Repository) (*[]ocispecs.ReferenceDescriptor, error) {
 	var references []ocispecs.ReferenceDescriptor
 	signatureTag, err := attachedImageTag(subjectReference, CosignSignatureTagSuffix)
@@ -47,7 +46,7 @@ func getCosignReferences(ctx context.Context, subjectReference common.Reference,
 			return nil, nil
 		}
 		evictOnError(ctx, err, subjectReference.Original)
-		return nil, err
+		return nil, re.ErrorCodeRepositoryOperationFailure.WithError(err).WithComponentType(re.ReferrerStore)
 	}
 
 	references = append(references, ocispecs.ReferenceDescriptor{
@@ -65,7 +64,7 @@ func getCosignReferences(ctx context.Context, subjectReference common.Reference,
 func attachedImageTag(subjectReference common.Reference, tagSuffix string) (string, error) {
 	// sha256:d34db33f -> sha256-d34db33f.suffix
 	if subjectReference.Digest.String() == "" {
-		return "", ErrNoCosignSubjectDigest
+		return "", re.ErrorCodeReferenceInvalid.WithComponentType(re.ReferrerStore).WithDetail("Cosign subject digest is empty")
 	}
 	tagStr := strings.ReplaceAll(subjectReference.Digest.String(), ":", "-") + tagSuffix
 	return fmt.Sprintf("%s:%s", subjectReference.Path, tagStr), nil
diff --git a/pkg/referrerstore/oras/oras.go b/pkg/referrerstore/oras/oras.go
index 1473b85..94f23e6 100644
--- a/pkg/referrerstore/oras/oras.go
+++ b/pkg/referrerstore/oras/oras.go
@@ -38,6 +38,7 @@ import (
 	"oras.land/oras-go/v2/registry/remote/retry"
 
 	ratifyconfig "github.com/deislabs/ratify/config"
+	re "github.com/deislabs/ratify/errors"
 	"github.com/deislabs/ratify/pkg/cache"
 	"github.com/deislabs/ratify/pkg/common"
 	"github.com/deislabs/ratify/pkg/common/oras/authprovider"
@@ -107,7 +108,7 @@ func (s *orasStoreFactory) Create(version string, storeConfig config.StorePlugin
 
 	cacheConf, err := toCacheConfig(storeBase.GetConfig().Store)
 	if err != nil {
-		return nil, err
+		return nil, re.ErrorCodeConfigInvalid.WithError(err).WithComponentType(re.ReferrerStore)
 	}
 	if !cacheConf.Enabled {
 		return storeBase, nil
@@ -121,16 +122,16 @@ func createBaseStore(version string, storeConfig config.StorePluginConfig) (*ora
 
 	storeConfigBytes, err := json.Marshal(storeConfig)
 	if err != nil {
-		return nil, err
+		return nil, re.ErrorCodeConfigInvalid.WithError(err).WithComponentType(re.ReferrerStore)
 	}
 
 	if err := json.Unmarshal(storeConfigBytes, &conf); err != nil {
-		return nil, fmt.Errorf("failed to parse oras store configuration: %w", err)
+		return nil, re.ErrorCodeConfigInvalid.NewError(re.ReferrerStore, "", re.EmptyLink, err, "failed to parse oras store configuration", re.HideStackTrace)
 	}
 
 	authenticationProvider, err := authprovider.CreateAuthProviderFromConfig(conf.AuthProvider)
 	if err != nil {
-		return nil, fmt.Errorf("failed to create auth provider from configuration: %w", err)
+		return nil, re.ErrorCodePluginInitFailure.NewError(re.ReferrerStore, "", re.EmptyLink, err, "failed to create auth provider from configuration", re.HideStackTrace)
 	}
 
 	// Set up the local cache where content will land when we pull
@@ -140,7 +141,7 @@ func createBaseStore(version string, storeConfig config.StorePluginConfig) (*ora
 
 	localRegistry, err := ocitarget.New(conf.LocalCachePath)
 	if err != nil {
-		return nil, fmt.Errorf("could not create local oras cache at path %s: %w", conf.LocalCachePath, err)
+		return nil, re.ErrorCodePluginInitFailure.WithError(err).WithComponentType(re.ReferrerStore).WithDetail(fmt.Sprintf("could not create local oras cache at path: %s", conf.LocalCachePath))
 	}
 
 	var customPredicate retry.Predicate = func(resp *http.Response, err error) (bool, error) {
@@ -204,7 +205,7 @@ func (store *orasStore) GetConfig() *config.StoreConfig {
 func (store *orasStore) ListReferrers(ctx context.Context, subjectReference common.Reference, _ []string, _ string, subjectDesc *ocispecs.SubjectDescriptor) (referrerstore.ListReferrersResult, error) {
 	repository, err := store.createRepository(ctx, store, subjectReference)
 	if err != nil {
-		return referrerstore.ListReferrersResult{}, err
+		return referrerstore.ListReferrersResult{}, re.ErrorCodeCreateRepositoryFailure.WithError(err).WithComponentType(re.ReferrerStore)
 	}
 
 	// resolve subject descriptor if not provided
@@ -295,7 +296,7 @@ func (store *orasStore) GetBlobContent(ctx context.Context, subjectReference com
 func (store *orasStore) GetReferenceManifest(ctx context.Context, subjectReference common.Reference, referenceDesc ocispecs.ReferenceDescriptor) (ocispecs.ReferenceManifest, error) {
 	repository, err := store.createRepository(ctx, store, subjectReference)
 	if err != nil {
-		return ocispecs.ReferenceManifest{}, err
+		return ocispecs.ReferenceManifest{}, re.ErrorCodeCreateRepositoryFailure.NewError(re.ReferrerStore, storeName, re.EmptyLink, err, nil, re.HideStackTrace)
 	}
 	var manifestBytes []byte
 	// check if manifest exists in local ORAS cache
@@ -310,12 +311,12 @@ func (store *orasStore) GetReferenceManifest(ctx context.Context, subjectReferen
 		manifestReader, err := repository.Fetch(ctx, referenceDesc.Descriptor)
 		if err != nil {
 			evictOnError(ctx, err, subjectReference.Original)
-			return ocispecs.ReferenceManifest{}, err
+			return ocispecs.ReferenceManifest{}, re.ErrorCodeRepositoryOperationFailure.NewError(re.ReferrerStore, storeName, re.EmptyLink, err, nil, re.HideStackTrace)
 		}
 
 		manifestBytes, err = io.ReadAll(manifestReader)
 		if err != nil {
-			return ocispecs.ReferenceManifest{}, err
+			return ocispecs.ReferenceManifest{}, re.ErrorCodeManifestInvalid.WithError(err).WithPluginName(storeName).WithComponentType(re.ReferrerStore)
 		}
 
 		// push fetched manifest to local ORAS cache
@@ -337,12 +338,12 @@ func (store *orasStore) GetReferenceManifest(ctx context.Context, subjectReferen
 	if referenceDesc.Descriptor.MediaType == oci.MediaTypeImageManifest {
 		var imageManifest oci.Manifest
 		if err := json.Unmarshal(manifestBytes, &imageManifest); err != nil {
-			return ocispecs.ReferenceManifest{}, err
+			return ocispecs.ReferenceManifest{}, re.ErrorCodeDataDecodingFailure.WithError(err).WithComponentType(re.ReferrerStore)
 		}
 		referenceManifest = commonutils.OciManifestToReferenceManifest(imageManifest)
 	} else if referenceDesc.Descriptor.MediaType == ocispecs.MediaTypeArtifactManifest {
 		if err := json.Unmarshal(manifestBytes, &referenceManifest); err != nil {
-			return ocispecs.ReferenceManifest{}, err
+			return ocispecs.ReferenceManifest{}, re.ErrorCodeDataDecodingFailure.WithError(err).WithComponentType(re.ReferrerStore)
 		}
 	} else {
 		return ocispecs.ReferenceManifest{}, fmt.Errorf("unsupported manifest media type: %s", referenceDesc.Descriptor.MediaType)
@@ -354,13 +355,13 @@ func (store *orasStore) GetReferenceManifest(ctx context.Context, subjectReferen
 func (store *orasStore) GetSubjectDescriptor(ctx context.Context, subjectReference common.Reference) (*ocispecs.SubjectDescriptor, error) {
 	repository, err := store.createRepository(ctx, store, subjectReference)
 	if err != nil {
-		return nil, err
+		return nil, re.ErrorCodeCreateRepositoryFailure.WithError(err).WithComponentType(re.ReferrerStore).WithPluginName(storeName)
 	}
 
 	desc, err := repository.Resolve(ctx, subjectReference.Original)
 	if err != nil {
 		evictOnError(ctx, err, subjectReference.Original)
-		return nil, err
+		return nil, re.ErrorCodeRepositoryOperationFailure.WithError(err).WithPluginName(storeName)
 	}
 
 	return &ocispecs.SubjectDescriptor{Descriptor: desc}, nil
@@ -402,7 +403,7 @@ func createDefaultRepository(ctx context.Context, store *orasStore, targetRef co
 	}
 	if cacheResponse != "" && found {
 		if err := json.Unmarshal([]byte(cacheResponse), &authConfig); err != nil {
-			logrus.Warningf("failed to unmarshal auth config cache value: %v", err)
+			logrus.Warning(re.ErrorCodeDataDecodingFailure.NewError(re.Cache, "", re.EmptyLink, err, fmt.Sprintf("failed to unmarshal auth config cache value: %s", cacheResponse), re.HideStackTrace))
 		} else {
 			logrus.Debug("auth cache hit")
 			cacheHit = true
@@ -418,7 +419,7 @@ func createDefaultRepository(ctx context.Context, store *orasStore, targetRef co
 			if cacheProvider != nil {
 				success := cacheProvider.SetWithTTL(ctx, fmt.Sprintf(cache.CacheKeyOrasAuth, artifactRef.Registry), authConfig, time.Until(authConfig.ExpiresOn))
 				if !success {
-					logrus.Warningf("failed to set auth cache for %s", artifactRef.Registry)
+					logrus.Warning(re.ErrorCodeCacheNotSet.WithComponentType(re.Cache).WithDetail(fmt.Sprintf("failed to set auth cache for %s", artifactRef.Registry)))
 				}
 			}
 		}
diff --git a/pkg/referrerstore/utils/utils.go b/pkg/referrerstore/utils/utils.go
index 1c0602b..86d9dca 100644
--- a/pkg/referrerstore/utils/utils.go
+++ b/pkg/referrerstore/utils/utils.go
@@ -17,8 +17,8 @@ package utils
 
 import (
 	"context"
-	"fmt"
 
+	"github.com/deislabs/ratify/errors"
 	"github.com/deislabs/ratify/pkg/common"
 	"github.com/deislabs/ratify/pkg/ocispecs"
 	"github.com/deislabs/ratify/pkg/referrerstore"
@@ -31,8 +31,8 @@ func ResolveSubjectDescriptor(ctx context.Context, stores *[]referrerstore.Refer
 		if err == nil {
 			return desc, nil
 		}
-		logrus.Warnf("failed to resolve the subject descriptor from store %s with error %v\n", referrerStore.Name(), err)
+		logrus.Warn(errors.ErrorCodeGetSubjectDescriptorFailure.NewError(errors.ReferrerStore, referrerStore.Name(), errors.EmptyLink, err, "failed to resolve the subject descriptor", errors.HideStackTrace))
 	}
 
-	return nil, fmt.Errorf("could not resolve descriptor for a subject from any stores")
+	return nil, errors.ErrorCodeReferrerStoreFailure.WithDetail("could not resolve descriptor for a subject from any stores").WithComponentType(errors.ReferrerStore)
 }
diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go
index 0f6909e..6ab0d23 100644
--- a/pkg/utils/utils.go
+++ b/pkg/utils/utils.go
@@ -21,6 +21,7 @@ import (
 
 	_ "crypto/sha256" // required package for digest.Parse
 
+	"github.com/deislabs/ratify/errors"
 	"github.com/deislabs/ratify/pkg/common"
 	"github.com/docker/distribution/reference"
 	"github.com/opencontainers/go-digest"
@@ -40,7 +41,7 @@ func ParseDigest(digestStr string) (digest.Digest, error) {
 func ParseSubjectReference(subRef string) (common.Reference, error) {
 	parseResult, err := reference.ParseDockerRef(subRef)
 	if err != nil {
-		return common.Reference{}, fmt.Errorf("failed to parse subject reference: %w", err)
+		return common.Reference{}, errors.ErrorCodeReferenceInvalid.WithDetail("failed to parse subject reference")
 	}
 
 	var subjectRef common.Reference
diff --git a/pkg/verifier/factory/factory.go b/pkg/verifier/factory/factory.go
index 624e7b8..1a0c911 100644
--- a/pkg/verifier/factory/factory.go
+++ b/pkg/verifier/factory/factory.go
@@ -16,12 +16,12 @@ limitations under the License.
 package factory
 
 import (
-	"errors"
 	"fmt"
 	"os"
 	"path"
 	"strings"
 
+	re "github.com/deislabs/ratify/errors"
 	pluginCommon "github.com/deislabs/ratify/pkg/common/plugin"
 	"github.com/deislabs/ratify/pkg/featureflag"
 	"github.com/deislabs/ratify/pkg/verifier"
@@ -53,12 +53,12 @@ func Register(name string, factory VerifierFactory) {
 func CreateVerifierFromConfig(verifierConfig config.VerifierConfig, configVersion string, pluginBinDir []string) (verifier.ReferenceVerifier, error) {
 	verifierName, ok := verifierConfig[types.Name]
 	if !ok {
-		return nil, fmt.Errorf("failed to find verifier name in the verifier config with key %s", "name")
+		return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("failed to find verifier name in the verifier config with key %s", "name"))
 	}
 
 	verifierNameStr := fmt.Sprintf("%s", verifierName)
 	if strings.ContainsRune(verifierNameStr, os.PathSeparator) {
-		return nil, fmt.Errorf("invalid plugin name for a verifier: %s", verifierNameStr)
+		return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("invalid plugin name for a verifier: %s", verifierNameStr))
 	}
 
 	// if source is specified, download the plugin
@@ -66,13 +66,13 @@ func CreateVerifierFromConfig(verifierConfig config.VerifierConfig, configVersio
 		if featureflag.DynamicPlugins.Enabled {
 			source, err := pluginCommon.ParsePluginSource(source)
 			if err != nil {
-				return nil, fmt.Errorf("failed to parse plugin source: %w", err)
+				return nil, re.ErrorCodeConfigInvalid.NewError(re.Verifier, "", re.EmptyLink, err, "failed to parse plugin source", re.HideStackTrace)
 			}
 
 			targetPath := path.Join(pluginBinDir[0], verifierNameStr)
 			err = pluginCommon.DownloadPlugin(source, targetPath)
 			if err != nil {
-				return nil, fmt.Errorf("failed to download plugin: %w", err)
+				return nil, re.ErrorCodeDownloadPluginFailure.NewError(re.Verifier, "", re.EmptyLink, err, "failed to download plugin", re.HideStackTrace)
 			}
 			logrus.Infof("downloaded verifier plugin %s from %s to %s", verifierNameStr, source.Artifact, targetPath)
 		} else {
@@ -96,11 +96,11 @@ func CreateVerifiersFromConfig(verifiersConfig config.VerifiersConfig, defaultPl
 
 	err := validateVerifiersConfig(&verifiersConfig)
 	if err != nil {
-		return nil, err
+		return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithError(err)
 	}
 
 	if len(verifiersConfig.Verifiers) == 0 {
-		return nil, errors.New("verifiers config should have at least one verifier")
+		return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail("verifiers config should have at least one verifier")
 	}
 
 	verifiers := make([]verifier.ReferenceVerifier, 0)
@@ -114,7 +114,7 @@ func CreateVerifiersFromConfig(verifiersConfig config.VerifiersConfig, defaultPl
 	for _, verifierConfig := range verifiersConfig.Verifiers {
 		verifier, err := CreateVerifierFromConfig(verifierConfig, verifiersConfig.Version, verifiersConfig.PluginBinDirs)
 		if err != nil {
-			return nil, err
+			return nil, re.ErrorCodePluginInitFailure.WithComponentType(re.Verifier).WithError(err)
 		}
 		verifiers = append(verifiers, verifier)
 	}
diff --git a/pkg/verifier/notation/notation.go b/pkg/verifier/notation/notation.go
index b8ba68c..1d36ab7 100644
--- a/pkg/verifier/notation/notation.go
+++ b/pkg/verifier/notation/notation.go
@@ -23,6 +23,7 @@ import (
 	"strings"
 
 	ratifyconfig "github.com/deislabs/ratify/config"
+	re "github.com/deislabs/ratify/errors"
 	"github.com/deislabs/ratify/pkg/common"
 	"github.com/deislabs/ratify/pkg/homedir"
 
@@ -72,12 +73,12 @@ func init() {
 func (f *notationPluginVerifierFactory) Create(_ string, verifierConfig config.VerifierConfig, pluginDirectory string) (verifier.ReferenceVerifier, error) {
 	conf, err := parseVerifierConfig(verifierConfig)
 	if err != nil {
-		return nil, err
+		return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName)
 	}
 
 	verfiyService, err := getVerifierService(conf, pluginDirectory)
 	if err != nil {
-		return nil, err
+		return nil, re.ErrorCodePluginInitFailure.WithComponentType(re.Verifier).WithPluginName(verifierName)
 	}
 
 	artifactTypes := strings.Split(conf.ArtifactTypes, ",")
@@ -108,22 +109,22 @@ func (v *notationPluginVerifier) Verify(ctx context.Context,
 
 	subjectDesc, err := store.GetSubjectDescriptor(ctx, subjectReference)
 	if err != nil {
-		return verifier.VerifierResult{IsSuccess: false}, fmt.Errorf("failed to resolve subject: %+v, err: %w", subjectReference, err)
+		return verifier.VerifierResult{IsSuccess: false}, re.ErrorCodeGetSubjectDescriptorFailure.NewError(re.ReferrerStore, store.Name(), re.EmptyLink, err, fmt.Sprintf("failed to resolve subject: %+v", subjectReference), re.HideStackTrace)
 	}
 
 	referenceManifest, err := store.GetReferenceManifest(ctx, subjectReference, referenceDescriptor)
 	if err != nil {
-		return verifier.VerifierResult{IsSuccess: false}, fmt.Errorf("failed to get reference manifest for reference: %s, err: %w", subjectReference.Original, err)
+		return verifier.VerifierResult{IsSuccess: false}, re.ErrorCodeGetReferenceManifestFailure.NewError(re.ReferrerStore, store.Name(), re.EmptyLink, err, fmt.Sprintf("failed to resolve reference manifest: %+v", referenceDescriptor), re.HideStackTrace)
 	}
 
 	if len(referenceManifest.Blobs) == 0 {
-		return verifier.VerifierResult{IsSuccess: false}, fmt.Errorf("no signature content found for referrer: %s@%s", subjectReference.Path, referenceDescriptor.Digest.String())
+		return verifier.VerifierResult{IsSuccess: false}, re.ErrorCodeSignatureNotFound.NewError(re.Verifier, verifierName, re.EmptyLink, nil, fmt.Sprintf("no signature content found for referrer: %s@%s", subjectReference.Path, referenceDescriptor.Digest.String()), re.HideStackTrace)
 	}
 
 	for _, blobDesc := range referenceManifest.Blobs {
 		refBlob, err := store.GetBlobContent(ctx, subjectReference, blobDesc.Digest)
 		if err != nil {
-			return verifier.VerifierResult{IsSuccess: false}, fmt.Errorf("failed to get blob content of digest: %s, err: %w", blobDesc.Digest, err)
+			return verifier.VerifierResult{IsSuccess: false}, re.ErrorCodeGetBlobContentFailure.NewError(re.ReferrerStore, store.Name(), re.EmptyLink, err, fmt.Sprintf("failed to get blob content of digest: %s", blobDesc.Digest), re.HideStackTrace)
 		}
 
 		// TODO: notation verify API only accepts digested reference now.
@@ -131,7 +132,7 @@ func (v *notationPluginVerifier) Verify(ctx context.Context,
 		subjectRef := fmt.Sprintf("%s@%s", subjectReference.Path, subjectReference.Digest.String())
 		outcome, err := v.verifySignature(ctx, subjectRef, blobDesc.MediaType, subjectDesc.Descriptor, refBlob)
 		if err != nil {
-			return verifier.VerifierResult{IsSuccess: false, Extensions: extensions}, fmt.Errorf("failed to verify signature, err: %w", err)
+			return verifier.VerifierResult{IsSuccess: false, Extensions: extensions}, re.ErrorCodeVerifySignatureFailure.NewError(re.Verifier, verifierName, re.NotationSpecLink, err, "failed to verify signature of digest", re.HideStackTrace)
 		}
 
 		// Note: notation verifier already validates certificate chain is not empty.
@@ -171,11 +172,11 @@ func parseVerifierConfig(verifierConfig config.VerifierConfig) (*NotationPluginV
 
 	verifierConfigBytes, err := json.Marshal(verifierConfig)
 	if err != nil {
-		return nil, err
+		return nil, re.ErrorCodeConfigInvalid.NewError(re.Verifier, verifierName, re.EmptyLink, err, nil, re.HideStackTrace)
 	}
 
 	if err := json.Unmarshal(verifierConfigBytes, &conf); err != nil {
-		return nil, fmt.Errorf("failed to unmarshal to notationPluginVerifierConfig from： %+v, err: %w", verifierConfig, err)
+		return nil, re.ErrorCodeConfigInvalid.NewError(re.Verifier, verifierName, re.EmptyLink, err, fmt.Sprintf("failed to unmarshal to notationPluginVerifierConfig from: %+v.", verifierConfig), re.HideStackTrace)
 	}
 
 	defaultCertsDir := paths.Join(homedir.Get(), ratifyconfig.ConfigFileDir, defaultCertPath)
diff --git a/pkg/verifier/plugin/plugin.go b/pkg/verifier/plugin/plugin.go
index 29650b5..947e239 100644
--- a/pkg/verifier/plugin/plugin.go
+++ b/pkg/verifier/plugin/plugin.go
@@ -22,6 +22,7 @@ import (
 	"os"
 	"strings"
 
+	re "github.com/deislabs/ratify/errors"
 	"github.com/deislabs/ratify/pkg/common"
 	pluginCommon "github.com/deislabs/ratify/pkg/common/plugin"
 	"github.com/deislabs/ratify/pkg/ocispecs"
@@ -47,7 +48,7 @@ type VerifierPlugin struct {
 func NewVerifier(version string, verifierConfig config.VerifierConfig, pluginPaths []string) (verifier.ReferenceVerifier, error) {
 	verifierName, ok := verifierConfig[types.Name]
 	if !ok {
-		return nil, fmt.Errorf("failed to find verifier name in the verifier config with key %s", "name")
+		return nil, re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("failed to find verifier name in the verifier config with key: %s", types.Name))
 	}
 
 	var nestedReferences []string
@@ -108,7 +109,7 @@ func (vp *VerifierPlugin) verifyReference(
 	referrerStoreConfig *rc.StoreConfig) (*verifier.VerifierResult, error) {
 	pluginPath, err := vp.executor.FindInPaths(vp.name, vp.path)
 	if err != nil {
-		return nil, err
+		return nil, re.ErrorCodePluginNotFound.NewError(re.Verifier, vp.name, re.EmptyLink, err, nil, re.HideStackTrace)
 	}
 
 	pluginArgs := VerifierPluginArgs{
@@ -125,12 +126,12 @@ func (vp *VerifierPlugin) verifyReference(
 
 	verifierConfigBytes, err := json.Marshal(inputConfig)
 	if err != nil {
-		return nil, err
+		return nil, re.ErrorCodeConfigInvalid.NewError(re.Verifier, vp.name, re.EmptyLink, err, nil, re.HideStackTrace)
 	}
 
 	stdoutBytes, err := vp.executor.ExecutePlugin(ctx, pluginPath, nil, verifierConfigBytes, pluginArgs.AsEnviron())
 	if err != nil {
-		return nil, err
+		return nil, re.ErrorCodeVerifySignatureFailure.NewError(re.Verifier, vp.name, re.EmptyLink, err, nil, re.HideStackTrace)
 	}
 
 	result, err := types.GetVerifierResult(stdoutBytes)


Test patch:
diff --git a/errors/types_test.go b/errors/types_test.go
new file mode 100644
index 0000000..4dc5dd6
--- /dev/null
+++ b/errors/types_test.go
@@ -0,0 +1,177 @@
+/*
+Copyright The Ratify Authors.
+Licensed 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 errors
+
+import (
+	"errors"
+	"strings"
+	"testing"
+)
+
+const (
+	testGroup         = "test-group"
+	testValue         = "test-value"
+	testMessage       = "test-message"
+	testDescription   = "test-description"
+	testDetail        = "test-detail"
+	testComponentType = "test-component-type"
+	testLink          = "test-link"
+	testPluginName    = "test-plugin-name"
+	testErrorString   = "Original Error: (Error: , Code: UNKNOWN), Error: test-message, Code: test-value, Plugin Name: test-plugin-name, Component Type: test-component-type, Documentation: test-link, Detail: test-detail"
+	nonexistentEC     = 2000
+)
+
+var (
+	testEC = Register(testGroup, ErrorDescriptor{
+		Value:       testValue,
+		Message:     testMessage,
+		Description: testDescription,
+	})
+
+	testEC2 = Register(testGroup, ErrorDescriptor{})
+)
+
+func TestErrorCode(t *testing.T) {
+	ec := ErrorCode(1)
+	if ec.ErrorCode() != 1 {
+		t.Fatalf("ErrorCode() should return 1")
+	}
+}
+
+func TestError(t *testing.T) {
+	if testEC.Error() != testValue {
+		t.Fatalf("expected: %s, got: %s", testValue, testEC.Error())
+	}
+}
+
+func TestDescriptor(t *testing.T) {
+	testCases := []struct {
+		name          string
+		ec            ErrorCode
+		expectedValue string
+	}{
+		{
+			name:          "existing error code",
+			ec:            testEC,
+			expectedValue: testValue,
+		},
+		{
+			name:          "nonexistent error code",
+			ec:            ErrorCode(nonexistentEC),
+			expectedValue: "UNKNOWN",
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			desc := tc.ec.Descriptor()
+			if desc.Value != tc.expectedValue {
+				t.Fatalf("expected value: %s, got: %s", tc.expectedValue, desc.Value)
+			}
+		})
+	}
+}
+
+func TestMessage(t *testing.T) {
+	if testEC.Message() != testMessage {
+		t.Fatalf("expected message: %s, got: %s", testMessage, testEC.Message())
+	}
+}
+
+func TestWithDetail(t *testing.T) {
+	err := testEC.WithDetail(testDetail)
+	if err.Detail != testDetail {
+		t.Fatalf("expected detail: %s, got: %s", testDetail, err.Detail)
+	}
+}
+
+func TestWithError(t *testing.T) {
+	err := testEC.WithError(testEC2)
+	if !errors.Is(errors.Unwrap(err), testEC2) {
+		t.Fatalf("expected error: %s, got: %s", testEC2, errors.Unwrap(err))
+	}
+}
+
+func TestWithComponentType(t *testing.T) {
+	err := testEC.WithComponentType(testComponentType)
+	if err.ComponentType != testComponentType {
+		t.Fatalf("expected component type: %s, got: %s", testComponentType, err.ComponentType)
+	}
+}
+
+func TestWithLinkToDoc(t *testing.T) {
+	err := testEC.WithLinkToDoc(testLink)
+	if err.LinkToDoc != testLink {
+		t.Fatalf("expected link to doc: %s, got: %s", testLink, err.LinkToDoc)
+	}
+}
+
+func TestWithPluginName(t *testing.T) {
+	err := testEC.WithPluginName(testPluginName)
+	if err.PluginName != testPluginName {
+		t.Fatalf("expected plugin name: %s, got: %s", testPluginName, err.PluginName)
+	}
+}
+
+func TestIs(t *testing.T) {
+	err := testEC.WithDetail(testDetail)
+	result := err.Is(err)
+	if !result {
+		t.Fatalf("expected true, got: %v", result)
+	}
+
+	err2 := errors.New(testMessage)
+	result = err.Is(err2)
+	if result {
+		t.Fatalf("expected false, got: %v", result)
+	}
+}
+
+func TestError_ErrorCode(t *testing.T) {
+	err := Error{
+		Code: 1,
+	}
+	if err.ErrorCode() != 1 {
+		t.Fatalf("expected 1, got: %d", err.ErrorCode())
+	}
+}
+
+func TestIsEmpty(t *testing.T) {
+	err := Error{}
+	if !err.IsEmpty() {
+		t.Fatalf("expected true, but got false")
+	}
+
+	if testEC.WithDetail("").IsEmpty() {
+		t.Fatalf("expected false, but got true")
+	}
+}
+
+func TestError_Error(t *testing.T) {
+	err := testEC.WithPluginName(testPluginName).WithComponentType(testComponentType).WithLinkToDoc(testLink).WithDetail(testDetail).WithError(Error{})
+	result := err.Error()
+	if !strings.HasPrefix(result, testErrorString) {
+		t.Fatalf("expected string starts with: %s, but got: %s", testErrorString, result)
+	}
+}
+
+func TestNewError(t *testing.T) {
+	err := testEC.NewError(testComponentType, testPluginName, testLink, Error{}, testDetail, false)
+
+	if err.ComponentType != testComponentType || err.PluginName != testPluginName || err.LinkToDoc != testLink || err.Detail != testDetail {
+		t.Fatalf("expected component type: %s, plugin name: %s, link to doc: %s, detail: %s, but got: %s, %s, %s, %s", testComponentType, testPluginName, testLink, testDetail, err.ComponentType, err.PluginName, err.LinkToDoc, err.Detail)
+	}
+}
diff --git a/httpserver/server_test.go b/httpserver/server_test.go
index 430baa9..52dfa9c 100644
--- a/httpserver/server_test.go
+++ b/httpserver/server_test.go
@@ -28,12 +28,11 @@ import (
 	"testing"
 	"time"
 
+	ratifyerrors "github.com/deislabs/ratify/errors"
 	exconfig "github.com/deislabs/ratify/pkg/executor/config"
 	"github.com/deislabs/ratify/pkg/executor/core"
 	"github.com/deislabs/ratify/pkg/ocispecs"
 	config "github.com/deislabs/ratify/pkg/policyprovider/configpolicy"
-	"github.com/docker/distribution/reference"
-	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 
 	"github.com/deislabs/ratify/pkg/policyprovider/types"
@@ -441,9 +440,9 @@ func TestServer_Verify_ParseReference_Failure(t *testing.T) {
 		if retFirstKey != testImageNames[0] {
 			t.Fatalf("Expected first subject response to be %s but got %s", testImageNames[0], retFirstKey)
 		}
-		expectedErr := errors.Wrap(reference.ErrReferenceInvalidFormat, "failed to parse subject reference")
-		if retFirstErr != expectedErr.Error() {
-			t.Fatalf("Expected first subject error to be %s but got %s", expectedErr.Error(), retFirstErr)
+		expectedErr := ratifyerrors.ErrorCodeReferenceInvalid.WithDetail("failed to parse subject reference").Error()
+		if retFirstErr != expectedErr {
+			t.Fatalf("Expected first subject error to be: %s,: but got %s", expectedErr, retFirstErr)
 		}
 	})
 }
diff --git a/pkg/certificateprovider/certificate_provider_test.go b/pkg/certificateprovider/certificate_provider_test.go
index 57c882d..a86e31a 100644
--- a/pkg/certificateprovider/certificate_provider_test.go
+++ b/pkg/certificateprovider/certificate_provider_test.go
@@ -16,8 +16,10 @@ limitations under the License.
 package certificateprovider
 
 import (
+	"errors"
 	"testing"
 
+	ratifyerrors "github.com/deislabs/ratify/errors"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -98,8 +100,8 @@ func TestDecodeCertificates_FailedToDecode(t *testing.T) {
 		t.Fatalf("DecodeCertificates should return an error")
 	}
 
-	expectedError := "failed to decode pem block"
-	if err.Error() != expectedError {
+	expectedError := ratifyerrors.ErrorCodeCertInvalid.WithDetail("failed to decode pem block")
+	if !errors.Is(err, expectedError) {
 		t.Fatalf("unexpected error, expected %+v, got %+v", expectedError, err.Error())
 	}
 }
@@ -114,8 +116,8 @@ func TestDecodeCertificates_FailedX509ParseError(t *testing.T) {
 		t.Fatalf("DecodeCertificates should return an error")
 	}
 
-	expectedError := "error parsing x509 certificate: x509: malformed issuer"
-	if err.Error() != expectedError {
+	expectedError := ratifyerrors.ErrorCodeCertInvalid.WithDetail("error parsing x509 certificate: x509: malformed issuer")
+	if !errors.Is(err, expectedError) {
 		t.Fatalf("unexpected error, expected %+v, got %+v", expectedError, err.Error())
 	}
 }
diff --git a/pkg/common/oras/authprovider/azure/azureidentity_test.go b/pkg/common/oras/authprovider/azure/azureidentity_test.go
index e524636..3bf0230 100644
--- a/pkg/common/oras/authprovider/azure/azureidentity_test.go
+++ b/pkg/common/oras/authprovider/azure/azureidentity_test.go
@@ -17,11 +17,12 @@ package azure
 
 import (
 	"context"
-	"fmt"
+	"errors"
 	"os"
 	"testing"
 
 	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
+	ratifyerrors "github.com/deislabs/ratify/errors"
 	"github.com/deislabs/ratify/pkg/common/oras/authprovider"
 )
 
@@ -71,8 +72,8 @@ func TestAzureMSIValidation_EnvironmentVariables_ExpectedResults(t *testing.T) {
 
 	_, err = authprovider.CreateAuthProviderFromConfig(authProviderConfig)
 
-	expectedErr := fmt.Errorf("AZURE_TENANT_ID environment variable is empty")
-	if err == nil || err.Error() != expectedErr.Error() {
+	expectedErr := ratifyerrors.ErrorCodeAuthDenied.WithDetail("AZURE_TENANT_ID environment variable is empty")
+	if err == nil || !errors.Is(err, expectedErr) {
 		t.Fatalf("create auth provider should have failed: expected err %s, but got err %s", expectedErr, err)
 	}
 
@@ -83,8 +84,8 @@ func TestAzureMSIValidation_EnvironmentVariables_ExpectedResults(t *testing.T) {
 
 	_, err = authprovider.CreateAuthProviderFromConfig(authProviderConfig)
 
-	expectedErr = fmt.Errorf("AZURE_CLIENT_ID environment variable is empty")
-	if err == nil || err.Error() != expectedErr.Error() {
+	expectedErr = ratifyerrors.ErrorCodeAuthDenied.WithDetail("AZURE_CLIENT_ID environment variable is empty")
+	if err == nil || !errors.Is(err, expectedErr) {
 		t.Fatalf("create auth provider should have failed: expected err %s, but got err %s", expectedErr, err)
 	}
 }
diff --git a/pkg/common/oras/authprovider/azure/azureworkloadidentity_test.go b/pkg/common/oras/authprovider/azure/azureworkloadidentity_test.go
index 08544da..0ac3ce8 100644
--- a/pkg/common/oras/authprovider/azure/azureworkloadidentity_test.go
+++ b/pkg/common/oras/authprovider/azure/azureworkloadidentity_test.go
@@ -17,12 +17,13 @@ package azure
 
 import (
 	"context"
-	"fmt"
+	"errors"
 	"os"
 	"testing"
 	"time"
 
 	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential"
+	ratifyerrors "github.com/deislabs/ratify/errors"
 	"github.com/deislabs/ratify/pkg/common/oras/authprovider"
 )
 
@@ -86,8 +87,8 @@ func TestAzureWIValidation_EnvironmentVariables_ExpectedResults(t *testing.T) {
 
 	_, err = authprovider.CreateAuthProviderFromConfig(authProviderConfig)
 
-	expectedErr := fmt.Errorf("azure tenant id environment variable is empty")
-	if err == nil || err.Error() != expectedErr.Error() {
+	expectedErr := ratifyerrors.ErrorCodeAuthDenied.WithDetail("azure tenant id environment variable is empty")
+	if err == nil || !errors.Is(err, expectedErr) {
 		t.Fatalf("create auth provider should have failed: expected err %s, but got err %s", expectedErr, err)
 	}
 
@@ -103,15 +104,15 @@ func TestAzureWIValidation_EnvironmentVariables_ExpectedResults(t *testing.T) {
 
 	_, err = authprovider.CreateAuthProviderFromConfig(authProviderConfigWithClientID)
 
-	expectedErr = fmt.Errorf("required environment variables not set, AZURE_FEDERATED_TOKEN_FILE: , AZURE_AUTHORITY_HOST: ")
-	if err == nil || err.Error() != expectedErr.Error() {
+	expectedErr = ratifyerrors.ErrorCodeAuthDenied.WithDetail("required environment variables not set, AZURE_FEDERATED_TOKEN_FILE: , AZURE_AUTHORITY_HOST: ")
+	if err == nil || !errors.Is(err, expectedErr) {
 		t.Fatalf("create auth provider should have failed: expected err %s, but got err %s", expectedErr, err)
 	}
 
 	_, err = authprovider.CreateAuthProviderFromConfig(authProviderConfig)
 
-	expectedErr = fmt.Errorf("no client ID provided and AZURE_CLIENT_ID environment variable is empty")
-	if err == nil || err.Error() != expectedErr.Error() {
+	expectedErr = ratifyerrors.ErrorCodeAuthDenied.WithDetail("no client ID provided and AZURE_CLIENT_ID environment variable is empty")
+	if err == nil || !errors.Is(err, expectedErr) {
 		t.Fatalf("create auth provider should have failed: expected err %s, but got err %s", expectedErr, err)
 	}
 
@@ -125,8 +126,8 @@ func TestAzureWIValidation_EnvironmentVariables_ExpectedResults(t *testing.T) {
 
 	_, err = authprovider.CreateAuthProviderFromConfig(authProviderConfig)
 
-	expectedErr = fmt.Errorf("required environment variables not set, AZURE_FEDERATED_TOKEN_FILE: , AZURE_AUTHORITY_HOST: ")
-	if err == nil || err.Error() != expectedErr.Error() {
+	expectedErr = ratifyerrors.ErrorCodeAuthDenied.WithDetail("required environment variables not set, AZURE_FEDERATED_TOKEN_FILE: , AZURE_AUTHORITY_HOST: ")
+	if err == nil || !errors.Is(err, expectedErr) {
 		t.Fatalf("create auth provider should have failed: expected err %s, but got err %s", expectedErr, err)
 	}
 }
diff --git a/pkg/common/oras/authprovider/k8secret_authprovider_test.go b/pkg/common/oras/authprovider/k8secret_authprovider_test.go
index a20d42d..12f5cc7 100644
--- a/pkg/common/oras/authprovider/k8secret_authprovider_test.go
+++ b/pkg/common/oras/authprovider/k8secret_authprovider_test.go
@@ -19,6 +19,7 @@ import (
 	"errors"
 	"testing"
 
+	ratifyerrors "github.com/deislabs/ratify/errors"
 	core "k8s.io/api/core/v1"
 )
 
@@ -69,7 +70,7 @@ func TestProvide_K8SecretNonExistentRegistry_ReturnsExpected(t *testing.T) {
 
 	var k8secretprovider k8SecretAuthProvider
 
-	if _, err := k8secretprovider.resolveCredentialFromSecret("nonexistent.ghcr.io", &testSecret); !errors.Is(err, ErrorNoMatchingCredential) {
-		t.Fatalf("resolveCredentialFromSecret should have failed to get credential with err %v but returned err %v", ErrorNoMatchingCredential, err)
+	if _, err := k8secretprovider.resolveCredentialFromSecret("nonexistent.ghcr.io", &testSecret); !errors.Is(err, ratifyerrors.ErrorCodeNoMatchingCredential) {
+		t.Fatalf("resolveCredentialFromSecret should have failed to get credential with err %v but returned err %v", ratifyerrors.ErrorCodeNoMatchingCredential, err)
 	}
 }
diff --git a/pkg/executor/core/executor_test.go b/pkg/executor/core/executor_test.go
index f40805a..0e66c89 100644
--- a/pkg/executor/core/executor_test.go
+++ b/pkg/executor/core/executor_test.go
@@ -22,13 +22,13 @@ import (
 	"testing"
 	"time"
 
+	ratifyerrors "github.com/deislabs/ratify/errors"
 	"github.com/deislabs/ratify/pkg/common"
-	exConfig "github.com/deislabs/ratify/pkg/executor/config"
-	"github.com/deislabs/ratify/pkg/policyprovider"
-
 	e "github.com/deislabs/ratify/pkg/executor"
+	exConfig "github.com/deislabs/ratify/pkg/executor/config"
 	"github.com/deislabs/ratify/pkg/executor/types"
 	"github.com/deislabs/ratify/pkg/ocispecs"
+	"github.com/deislabs/ratify/pkg/policyprovider"
 	policyConfig "github.com/deislabs/ratify/pkg/policyprovider/configpolicy"
 	policyTypes "github.com/deislabs/ratify/pkg/policyprovider/types"
 	pt "github.com/deislabs/ratify/pkg/policyprovider/types"
@@ -184,7 +184,7 @@ func TestVerifySubjectInternal_ResolveSubjectDescriptor_Success(t *testing.T) {
 		Subject: "localhost:5000/net-monitor:v1",
 	}
 
-	if _, err := executor.verifySubjectInternal(context.Background(), verifyParameters); !errors.Is(err, ErrReferrersNotFound) {
+	if _, err := executor.verifySubjectInternal(context.Background(), verifyParameters); !errors.Is(err, ratifyerrors.ErrorCodeReferrersNotFound.WithDetail("")) {
 		t.Fatalf("expected ErrReferrersNotFound actual %v", err)
 	}
 }
@@ -210,7 +210,7 @@ func TestVerifySubjectInternal_Verify_NoReferrers(t *testing.T) {
 		Subject: "localhost:5000/net-monitor:v1",
 	}
 
-	if _, err := ex.verifySubjectInternal(context.Background(), verifyParameters); !errors.Is(err, ErrReferrersNotFound) {
+	if _, err := ex.verifySubjectInternal(context.Background(), verifyParameters); !errors.Is(err, ratifyerrors.ErrorCodeReferrersNotFound.WithDetail("")) {
 		t.Fatalf("expected ErrReferrersNotFound actual %v", err)
 	}
 }
diff --git a/pkg/referrerstore/oras/cosign_test.go b/pkg/referrerstore/oras/cosign_test.go
index 5314e58..3e87c00 100644
--- a/pkg/referrerstore/oras/cosign_test.go
+++ b/pkg/referrerstore/oras/cosign_test.go
@@ -23,6 +23,7 @@ import (
 	"reflect"
 	"testing"
 
+	ratifyerrors "github.com/deislabs/ratify/errors"
 	"github.com/deislabs/ratify/pkg/cache"
 	_ "github.com/deislabs/ratify/pkg/cache/ristretto"
 	"github.com/deislabs/ratify/pkg/common"
@@ -58,13 +59,13 @@ func TestAttachedImageTag(t *testing.T) {
 				Path: "localhost:5000/net-monitor",
 				Tag:  "v1",
 			},
-			err: ErrNoCosignSubjectDigest,
+			err: ratifyerrors.ErrorCodeReferenceInvalid.WithDetail(""),
 		},
 	}
 
 	for _, testcase := range testcases {
 		mutated, err := attachedImageTag(testcase.input, CosignSignatureTagSuffix)
-		if err != nil && !errors.Is(err, ErrNoCosignSubjectDigest) {
+		if err != nil && !errors.Is(err, testcase.err) {
 			t.Fatalf("expected error to be %v, but got %v", testcase.err, err)
 		}
 		if mutated != testcase.output {
@@ -106,7 +107,7 @@ func TestGetCosignReferences(t *testing.T) {
 			},
 			repository: mocks.TestRepository{},
 			output:     nil,
-			err:        ErrNoCosignSubjectDigest,
+			err:        ratifyerrors.ErrorCodeReferenceInvalid.WithDetail(""),
 		},
 		{
 			name: "no cosign references",
@@ -160,7 +161,7 @@ func TestGetCosignReferences(t *testing.T) {
 				ResolveErr: nonStandardError,
 			},
 			output: nil,
-			err:    nonStandardError,
+			err:    ratifyerrors.ErrorCodeRepositoryOperationFailure.WithDetail(""),
 		},
 		{
 			name: "resolve error forbidden error code",
@@ -174,7 +175,7 @@ func TestGetCosignReferences(t *testing.T) {
 				ResolveErr: forbiddenError,
 			},
 			output: nil,
-			err:    forbiddenError,
+			err:    ratifyerrors.ErrorCodeRepositoryOperationFailure.WithDetail(""),
 		},
 		{
 			name: "resolve error unauthorized error code",
@@ -188,7 +189,7 @@ func TestGetCosignReferences(t *testing.T) {
 				ResolveErr: unauthorizedError,
 			},
 			output: nil,
-			err:    unauthorizedError,
+			err:    ratifyerrors.ErrorCodeRepositoryOperationFailure.WithDetail(""),
 		},
 	}
 	for _, testcase := range testcases {