Repository: aws/aws-toolkit-jetbrains
Pull request #5498: telemetry(amazonq): Added metric data for /doc and improved error cla…
Author: login: KevinDing1
Created: 2025-03-24T18:48:28Z | Merged: 2025-03-31T21:54:34Z

…ssification

<!--- If you are a new contributor, please take a look at the README and CONTRIBUTING documents --->
<!--- Provide a general summary of your changes in the Title above -->

## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)

## Description
<!--- Describe your changes in detail -->
- This commit introduces metric telemetry for the /doc, which will be triggered during the code generation process. The new telemetry will:
  1. Record successful and failure generation requests
  2. Track failed requests with specific error types
  3. Enable the setup of client monitoring alarms base on the metric data
- Improve the error classification for /doc base on /dev's change: https://github.com/aws/aws-toolkit-jetbrains/pull/5469

These enhancements will provide better insights into client performance
<!--- If appropriate, providing screenshots will help us review your contribution -->
<!--- If there is a related issue, please provide a link here -->

## Checklist
- [X] My code follows the code style of this project
- [ ] I have added tests to cover my changes
- [ ] A short description of the change has been added to the **[CHANGELOG](https://github.com/aws/aws-toolkit-jetbrains/blob/master/CONTRIBUTING.md#contributing-via-pull-requests)** if the change is customer-facing in the IDE.
- [ ] I have added metrics for my changes (if required)
 
## License
I confirm that my contribution is made under the terms of the Apache 2.0 license.



Diff:
diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/common/clients/AmazonQCodeGenerateClient.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/common/clients/AmazonQCodeGenerateClient.kt
index b6b192531e8..2c28c3240f3 100644
--- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/common/clients/AmazonQCodeGenerateClient.kt
+++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/common/clients/AmazonQCodeGenerateClient.kt
@@ -13,6 +13,7 @@ import software.amazon.awssdk.services.codewhispererruntime.model.ContentChecksu
 import software.amazon.awssdk.services.codewhispererruntime.model.CreateTaskAssistConversationRequest
 import software.amazon.awssdk.services.codewhispererruntime.model.CreateTaskAssistConversationResponse
 import software.amazon.awssdk.services.codewhispererruntime.model.CreateUploadUrlResponse
+import software.amazon.awssdk.services.codewhispererruntime.model.Dimension
 import software.amazon.awssdk.services.codewhispererruntime.model.DocV2AcceptanceEvent
 import software.amazon.awssdk.services.codewhispererruntime.model.DocV2GenerationEvent
 import software.amazon.awssdk.services.codewhispererruntime.model.GetTaskAssistCodeGenerationResponse
@@ -89,6 +90,33 @@ class AmazonQCodeGenerateClient(private val project: Project) {
             requestBuilder.userContext(docUserContext)
         }
 
+    fun sendDocMetricData(operationName: String, result: String): SendTelemetryEventResponse =
+        bearerClient().sendTelemetryEvent { requestBuilder ->
+            requestBuilder.telemetryEvent { telemetryEventBuilder ->
+                telemetryEventBuilder.metricData {
+                    it
+                        .metricName("Operation")
+                        .metricValue(1.0)
+                        .timestamp(Instant.now())
+                        .product("DocGeneration")
+                        .dimensions(
+                            listOf(
+                                Dimension.builder()
+                                    .name("operationName")
+                                    .value(operationName)
+                                    .build(),
+                                Dimension.builder()
+                                    .name("result")
+                                    .value(result)
+                                    .build()
+                            )
+                        )
+                }
+            }
+            requestBuilder.optOutPreference(getTelemetryOptOutPreference())
+            requestBuilder.userContext(docUserContext)
+        }
+
     fun createTaskAssistConversation(): CreateTaskAssistConversationResponse = bearerClient().createTaskAssistConversation(
         CreateTaskAssistConversationRequest.builder().build()
     )
diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/common/util/AmazonQCodeGenService.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/common/util/AmazonQCodeGenService.kt
index 58ebb32b958..299e9c5ba57 100644
--- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/common/util/AmazonQCodeGenService.kt
+++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/common/util/AmazonQCodeGenService.kt
@@ -20,7 +20,6 @@ import software.aws.toolkits.core.utils.getLogger
 import software.aws.toolkits.core.utils.warn
 import software.aws.toolkits.jetbrains.common.clients.AmazonQCodeGenerateClient
 import software.aws.toolkits.jetbrains.common.session.Intent
-import software.aws.toolkits.jetbrains.services.amazonqDoc.docServiceError
 import software.aws.toolkits.jetbrains.services.amazonqDoc.session.DocGenerationStreamResult
 import software.aws.toolkits.jetbrains.services.amazonqDoc.session.ExportDocTaskAssistResultArchiveStreamResult
 import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ApiException
@@ -34,9 +33,9 @@ import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.MonthlyConvers
 import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ServiceException
 import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ZipFileCorruptedException
 import software.aws.toolkits.jetbrains.services.cwc.controller.chat.telemetry.getStartUrl
-import software.aws.toolkits.resources.message
 import software.aws.toolkits.telemetry.AmazonqTelemetry
 import software.aws.toolkits.telemetry.MetricResult
+import software.aws.toolkits.jetbrains.services.amazonqDoc.ContentLengthException as DocContentLengthException
 
 class AmazonQCodeGenService(val proxyClient: AmazonQCodeGenerateClient, val project: Project) {
     fun createConversation(): String {
@@ -115,7 +114,7 @@ class AmazonQCodeGenService(val proxyClient: AmazonQCodeGenerateClient, val proj
 
                 if (e is ValidationException && e.message?.contains("Invalid contentLength") == true) {
                     if (featureName?.equals("docGeneration") == true) {
-                        throw docServiceError(message("amazonqDoc.exception.content_length_error"))
+                        throw DocContentLengthException(operation = FeatureDevOperation.CreateUploadUrl.toString(), desc = null, cause = e.cause)
                     }
                     throw ContentLengthException(operation = FeatureDevOperation.CreateUploadUrl.toString(), desc = null, cause = e.cause)
                 }
@@ -162,6 +161,9 @@ class AmazonQCodeGenService(val proxyClient: AmazonQCodeGenerateClient, val proj
                 ) {
                     throw CodeIterationLimitException(operation = FeatureDevOperation.StartTaskAssistCodeGeneration.toString(), desc = null, e.cause)
                 } else if (e is ValidationException && e.message?.contains("repo size is exceeding the limits") == true) {
+                    if (intent == Intent.DOC) {
+                        throw DocContentLengthException(operation = FeatureDevOperation.CreateUploadUrl.toString(), desc = null, cause = e.cause)
+                    }
                     throw ContentLengthException(operation = FeatureDevOperation.StartTaskAssistCodeGeneration.toString(), desc = null, cause = e.cause)
                 } else if (e is ValidationException && e.message?.contains("zipped file is corrupted") == true) {
                     throw ZipFileCorruptedException(operation = FeatureDevOperation.StartTaskAssistCodeGeneration.toString(), desc = null, e.cause)
diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/DocConstants.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/DocConstants.kt
index c85dc11101e..4cb612faf4c 100644
--- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/DocConstants.kt
+++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/DocConstants.kt
@@ -21,3 +21,21 @@ const val DIAGRAM_SVG_EXT = "svg"
 const val DIAGRAM_DOT_EXT = "dot"
 val SUPPORTED_DIAGRAM_EXT_SET: Set<String> = setOf(DIAGRAM_SVG_EXT, DIAGRAM_DOT_EXT)
 val SUPPORTED_DIAGRAM_FILE_NAME_SET: Set<String> = SUPPORTED_DIAGRAM_EXT_SET.map { INFRA_DIAGRAM_PREFIX + it }.toSet()
+
+enum class MetricDataOperationName(private val operationName: String) {
+    StartDocGeneration("StartDocGeneration"),
+    EndDocGeneration("EndDocGeneration"),
+    ;
+
+    override fun toString(): String = operationName
+}
+
+enum class MetricDataResult(private val resultName: String) {
+    Success("Success"),
+    Fault("Fault"),
+    Error("Error"),
+    LlmFailure("LLMFailure"),
+    ;
+
+    override fun toString(): String = resultName
+}
diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/DocExceptions.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/DocExceptions.kt
index 32fb297650b..37f44f1b0af 100644
--- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/DocExceptions.kt
+++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/DocExceptions.kt
@@ -3,24 +3,93 @@
 
 package software.aws.toolkits.jetbrains.services.amazonqDoc
 
+import software.aws.toolkits.jetbrains.services.amazonq.project.RepoSizeError
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ClientException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.LlmException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ServiceException
 import software.aws.toolkits.resources.message
 
-open class DocException(
-    override val message: String?,
-    override val cause: Throwable? = null,
+open class DocClientException(
+    message: String,
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
     val remainingIterations: Int? = null,
-) : RuntimeException()
+) : ClientException(message, operation, desc, cause)
 
-class ZipFileError(override val message: String, override val cause: Throwable?) : RuntimeException()
+val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
+fun createUserFacingErrorMessage(message: String?): String? =
+    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
 
-class CodeIterationLimitError(override val message: String, override val cause: Throwable?) : RuntimeException()
+class ReadmeTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun docServiceError(message: String?, cause: Throwable? = null, remainingIterations: Int? = null): Nothing =
-    throw DocException(message, cause, remainingIterations)
+class ReadmeUpdateTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_update_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun conversationIdNotFound(): Nothing =
-    throw DocException(message("amazonqFeatureDev.exception.conversation_not_found"))
+class ContentLengthException(
+    override val message: String = message("amazonqDoc.exception.content_length_error"),
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) :
+    RepoSizeError, ClientException(message, operation, desc, cause)
 
-val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
-fun createUserFacingErrorMessage(message: String?): String? =
-    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
+class WorkspaceEmptyException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.exception.workspace_empty"), operation, desc, cause)
+
+class PromptUnrelatedException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.prompt_unrelated"), operation, desc, cause, remainingIterations)
+
+class PromptTooVagueException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.prompt_too_vague"), operation, desc, cause, remainingIterations)
+
+class PromptRefusalException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqFeatureDev.exception.prompt_refusal"), operation, desc, cause, remainingIterations)
+
+class GuardrailsException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.error_text"), operation, desc, cause)
+
+class NoChangeRequiredException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.exception.no_change_required"), operation, desc, cause)
+
+class EmptyPatchException(operation: String, desc: String?, cause: Throwable? = null) :
+    LlmException(message("amazonqDoc.error_text"), operation, desc, cause)
+
+class ThrottlingException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqFeatureDev.exception.throttling"), operation, desc, cause)
+
+class DocGenerationException(operation: String, desc: String?, cause: Throwable? = null) :
+    ServiceException(message("amazonqDoc.error_text"), operation, desc, cause)
diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/controller/DocController.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/controller/DocController.kt
index 88abc4d2268..cd3c37b450a 100644
--- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/controller/DocController.kt
+++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/controller/DocController.kt
@@ -34,10 +34,11 @@ import software.aws.toolkits.jetbrains.services.amazonq.project.RepoSizeError
 import software.aws.toolkits.jetbrains.services.amazonq.toolwindow.AmazonQToolWindowFactory
 import software.aws.toolkits.jetbrains.services.amazonqDoc.DEFAULT_RETRY_LIMIT
 import software.aws.toolkits.jetbrains.services.amazonqDoc.DIAGRAM_SVG_EXT
-import software.aws.toolkits.jetbrains.services.amazonqDoc.DocException
+import software.aws.toolkits.jetbrains.services.amazonqDoc.DocClientException
 import software.aws.toolkits.jetbrains.services.amazonqDoc.FEATURE_NAME
 import software.aws.toolkits.jetbrains.services.amazonqDoc.InboundAppMessagesHandler
-import software.aws.toolkits.jetbrains.services.amazonqDoc.ZipFileError
+import software.aws.toolkits.jetbrains.services.amazonqDoc.MetricDataOperationName
+import software.aws.toolkits.jetbrains.services.amazonqDoc.MetricDataResult
 import software.aws.toolkits.jetbrains.services.amazonqDoc.cancellingProgressField
 import software.aws.toolkits.jetbrains.services.amazonqDoc.createUserFacingErrorMessage
 import software.aws.toolkits.jetbrains.services.amazonqDoc.denyListedErrors
@@ -70,6 +71,7 @@ import software.aws.toolkits.jetbrains.services.amazonqDoc.storage.ChatSessionSt
 import software.aws.toolkits.jetbrains.services.amazonqDoc.util.getFollowUpOptions
 import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.CodeIterationLimitException
 import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.MonthlyConversationLimitError
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ZipFileCorruptedException
 import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.CodeReferenceGenerated
 import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.DeletedFileInfo
 import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.NewFileZipInfo
@@ -592,9 +594,12 @@ class DocController(
         messenger.sendUpdatePlaceholder(tabId, message("amazonqFeatureDev.placeholder.provide_code_feedback"))
     }
 
-    private suspend fun processErrorChatMessage(err: Exception, session: DocSession?, tabId: String, isEnableChatInput: Boolean) {
+    private suspend fun processErrorChatMessage(err: Exception, session: DocSession?, tabId: String) {
         logger.warn(err) { "Encountered ${err.message} for tabId: $tabId" }
         messenger.sendUpdatePromptProgress(tabId, null)
+        val docGenerationMode = docGenerationTasks.getTask(tabId).mode
+        val isEnableChatInput = docGenerationMode == Mode.EDIT &&
+            (err as? DocClientException)?.remainingIterations?.let { it > 0 } ?: false
 
         when (err) {
             is RepoSizeError -> {
@@ -616,7 +621,7 @@ class DocController(
                 )
             }
 
-            is ZipFileError -> {
+            is ZipFileCorruptedException -> {
                 messenger.sendError(
                     tabId = tabId,
                     errMessage = err.message,
@@ -626,12 +631,11 @@ class DocController(
             }
 
             is MonthlyConversationLimitError -> {
-                messenger.sendUpdatePlaceholder(tabId, newPlaceholder = message("amazonqFeatureDev.placeholder.after_monthly_limit"))
-                messenger.sendChatInputEnabledMessage(tabId, enabled = true)
                 messenger.sendMonthlyLimitError(tabId = tabId)
+                messenger.sendChatInputEnabledMessage(tabId, enabled = false)
             }
 
-            is DocException -> {
+            is DocClientException -> {
                 messenger.sendErrorToUser(
                     tabId = tabId,
                     errMessage = err.message,
@@ -765,13 +769,7 @@ class DocController(
                 )
             }
         } catch (err: Exception) {
-            // For non edit mode lock the chat input until they explicitly click one of the follow-ups
-            var isEnableChatInput = false
-            if (err is DocException && docGenerationTask.mode == Mode.EDIT) {
-                isEnableChatInput = err.remainingIterations != null && err.remainingIterations > 0
-            }
-
-            processErrorChatMessage(err, session, tabId, isEnableChatInput)
+            processErrorChatMessage(err, session, tabId)
         }
     }
 
@@ -794,6 +792,10 @@ class DocController(
             }
 
             session.send(sessionMessage)
+            session.sendDocMetricData(
+                MetricDataOperationName.StartDocGeneration,
+                MetricDataResult.Success
+            )
 
             val filePaths: List<NewFileZipInfo> = when (val state = session.sessionState) {
                 is PrepareDocGenerationState -> state.filePaths ?: emptyList()
@@ -854,7 +856,11 @@ class DocController(
                 message = IncomingDocMessage.OpenDiff(tabId = followUpMessage.tabId, filePath = filePaths[0].zipFilePath, deleted = false)
             )
         } catch (err: Exception) {
-            processErrorChatMessage(err, session, tabId = followUpMessage.tabId, false)
+            session.sendDocMetricData(
+                MetricDataOperationName.EndDocGeneration,
+                session.getMetricResult(err)
+            )
+            processErrorChatMessage(err, session, tabId = followUpMessage.tabId)
         } finally {
             messenger.sendUpdatePlaceholder(
                 tabId = followUpMessage.tabId,
@@ -873,6 +879,10 @@ class DocController(
                 messenger.sendChatInputEnabledMessage(tabId = followUpMessage.tabId, enabled = false) // Lock chat input until a follow-up is clicked.
             }
         }
+        session.sendDocMetricData(
+            MetricDataOperationName.EndDocGeneration,
+            MetricDataResult.Success
+        )
     }
 
     private suspend fun handleEmptyFiles(
diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/controller/DocControllerExtensions.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/controller/DocControllerExtensions.kt
index 69fd1b032e8..eaacd4b0bb1 100644
--- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/controller/DocControllerExtensions.kt
+++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/controller/DocControllerExtensions.kt
@@ -4,6 +4,8 @@
 package software.aws.toolkits.jetbrains.services.amazonqDoc.controller
 
 import com.intellij.notification.NotificationAction
+import software.aws.toolkits.jetbrains.services.amazonqDoc.MetricDataOperationName
+import software.aws.toolkits.jetbrains.services.amazonqDoc.MetricDataResult
 import software.aws.toolkits.jetbrains.services.amazonqDoc.inProgress
 import software.aws.toolkits.jetbrains.services.amazonqDoc.messages.DocMessageType
 import software.aws.toolkits.jetbrains.services.amazonqDoc.messages.FollowUp
@@ -19,7 +21,6 @@ import software.aws.toolkits.jetbrains.services.amazonqDoc.messages.sendUpdatePr
 import software.aws.toolkits.jetbrains.services.amazonqDoc.session.DocSession
 import software.aws.toolkits.jetbrains.services.amazonqDoc.session.PrepareDocGenerationState
 import software.aws.toolkits.jetbrains.services.amazonqDoc.util.getFollowUpOptions
-import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.messages.sendSystemPrompt
 import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.CodeReferenceGenerated
 import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.DeletedFileInfo
 import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.NewFileZipInfo
@@ -52,6 +53,10 @@ suspend fun DocController.onCodeGeneration(session: DocSession, message: String,
         }
 
         val state = session.sessionState
+        session.sendDocMetricData(
+            MetricDataOperationName.StartDocGeneration,
+            MetricDataResult.Success
+        )
 
         var filePaths: List<NewFileZipInfo> = emptyList()
         var deletedFiles: List<DeletedFileInfo> = emptyList()
@@ -119,6 +124,12 @@ suspend fun DocController.onCodeGeneration(session: DocSession, message: String,
         messenger.sendSystemPrompt(tabId = tabId, followUp = getFollowUpOptions(session.sessionState.phase))
 
         messenger.sendUpdatePlaceholder(tabId = tabId, newPlaceholder = message("amazonqFeatureDev.placeholder.after_code_generation"))
+    } catch (err: Exception) {
+        session.sendDocMetricData(
+            MetricDataOperationName.EndDocGeneration,
+            session.getMetricResult(err)
+        )
+        throw err
     } finally {
         messenger.sendAsyncEventProgress(tabId = tabId, inProgress = false) // Finish processing the event
         messenger.sendChatInputEnabledMessage(tabId = tabId, enabled = false) // Lock chat input until a follow-up is clicked.
@@ -132,6 +143,10 @@ suspend fun DocController.onCodeGeneration(session: DocSession, message: String,
             )
         }
     }
+    session.sendDocMetricData(
+        MetricDataOperationName.EndDocGeneration,
+        MetricDataResult.Success
+    )
 }
 
 private fun DocController.openChatNotificationAction() = NotificationAction.createSimple(
diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/session/DocGenerationState.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/session/DocGenerationState.kt
index 30022067822..49bb81617e8 100644
--- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/session/DocGenerationState.kt
+++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/session/DocGenerationState.kt
@@ -11,14 +11,26 @@ import software.aws.toolkits.jetbrains.common.session.Intent
 import software.aws.toolkits.jetbrains.common.session.SessionState
 import software.aws.toolkits.jetbrains.common.session.SessionStateConfig
 import software.aws.toolkits.jetbrains.services.amazonq.messages.MessagePublisher
+import software.aws.toolkits.jetbrains.services.amazonqDoc.ContentLengthException
+import software.aws.toolkits.jetbrains.services.amazonqDoc.DocGenerationException
+import software.aws.toolkits.jetbrains.services.amazonqDoc.EmptyPatchException
 import software.aws.toolkits.jetbrains.services.amazonqDoc.FEATURE_NAME
+import software.aws.toolkits.jetbrains.services.amazonqDoc.GuardrailsException
+import software.aws.toolkits.jetbrains.services.amazonqDoc.NoChangeRequiredException
+import software.aws.toolkits.jetbrains.services.amazonqDoc.PromptRefusalException
+import software.aws.toolkits.jetbrains.services.amazonqDoc.PromptTooVagueException
+import software.aws.toolkits.jetbrains.services.amazonqDoc.PromptUnrelatedException
+import software.aws.toolkits.jetbrains.services.amazonqDoc.ReadmeTooLargeException
+import software.aws.toolkits.jetbrains.services.amazonqDoc.ReadmeUpdateTooLargeException
+import software.aws.toolkits.jetbrains.services.amazonqDoc.ThrottlingException
+import software.aws.toolkits.jetbrains.services.amazonqDoc.WorkspaceEmptyException
 import software.aws.toolkits.jetbrains.services.amazonqDoc.controller.DocGenerationStep
 import software.aws.toolkits.jetbrains.services.amazonqDoc.controller.Mode
 import software.aws.toolkits.jetbrains.services.amazonqDoc.controller.docGenerationProgressMessage
-import software.aws.toolkits.jetbrains.services.amazonqDoc.docServiceError
 import software.aws.toolkits.jetbrains.services.amazonqDoc.inProgress
 import software.aws.toolkits.jetbrains.services.amazonqDoc.messages.sendAnswerPart
 import software.aws.toolkits.jetbrains.services.amazonqDoc.messages.sendUpdatePromptProgress
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.FeatureDevOperation
 import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.CodeGenerationResult
 import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.Interaction
 import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.SessionStateAction
@@ -178,59 +190,97 @@ private suspend fun DocGenerationState.generateCode(codeGenerationId: String, mo
                     codeGenerationResultState.codeGenerationStatusDetail()?.contains(
                         "README_TOO_LARGE"
                     ),
-                    -> docServiceError(message("amazonqDoc.exception.readme_too_large"), remainingIterations = remainingIterations)
+                    -> throw ReadmeTooLargeException(
+                        operation = FeatureDevOperation.GenerateCode.toString(),
+                        desc = "Readme too large",
+                        remainingIterations = remainingIterations
+                    )
 
                     codeGenerationResultState.codeGenerationStatusDetail()?.contains(
                         "README_UPDATE_TOO_LARGE"
                     ),
-                    -> docServiceError(message("amazonqDoc.exception.readme_update_too_large"), remainingIterations = remainingIterations)
+                    -> throw ReadmeUpdateTooLargeException(
+                        operation = FeatureDevOperation.GenerateCode.toString(),
+                        desc = "Readme update too large",
+                        remainingIterations = remainingIterations
+                    )
 
                     codeGenerationResultState.codeGenerationStatusDetail()?.contains(
                         "WORKSPACE_TOO_LARGE"
                     ),
-                    -> docServiceError(message("amazonqDoc.exception.content_length_error"))
+                    -> throw ContentLengthException(
+                        operation = FeatureDevOperation.GenerateCode.toString(),
+                        desc = "Workspace too large"
+                    )
 
                     codeGenerationResultState.codeGenerationStatusDetail()?.contains(
                         "WORKSPACE_EMPTY"
                     ),
-                    -> docServiceError(message("amazonqDoc.exception.workspace_empty"))
+                    -> throw WorkspaceEmptyException(
+                        operation = FeatureDevOperation.GenerateCode.toString(),
+                        desc = "Workspace empty"
+                    )
 
                     codeGenerationResultState.codeGenerationStatusDetail()?.contains(
                         "PROMPT_UNRELATED"
                     ),
-                    -> docServiceError(message("amazonqDoc.exception.prompt_unrelated"), remainingIterations = remainingIterations)
+                    -> throw PromptUnrelatedException(
+                        operation = FeatureDevOperation.GenerateCode.toString(),
+                        desc = "Prompt unrelated",
+                        remainingIterations = remainingIterations
+                    )
 
                     codeGenerationResultState.codeGenerationStatusDetail()?.contains(
                         "PROMPT_TOO_VAGUE"
                     ),
-                    -> docServiceError(message("amazonqDoc.exception.prompt_too_vague"), remainingIterations = remainingIterations)
+                    -> throw PromptTooVagueException(
+                        operation = FeatureDevOperation.GenerateCode.toString(),
+                        desc = "Prompt too vague",
+                        remainingIterations = remainingIterations
+                    )
 
                     codeGenerationResultState.codeGenerationStatusDetail()?.contains(
                         "PromptRefusal"
                     ),
-                    -> docServiceError(message("amazonqFeatureDev.exception.prompt_refusal"), remainingIterations = remainingIterations)
+                    -> throw PromptRefusalException(
+                        operation = FeatureDevOperation.GenerateCode.toString(),
+                        desc = "Prompt refusal",
+                        remainingIterations = remainingIterations
+                    )
 
                     codeGenerationResultState.codeGenerationStatusDetail()?.contains(
                         "Guardrails"
                     ),
-                    -> docServiceError(message("amazonqDoc.error_text"))
+                    -> throw GuardrailsException(
+                        operation = FeatureDevOperation.GenerateCode.toString(),
+                        desc = "Guardrails violation"
+                    )
 
                     codeGenerationResultState.codeGenerationStatusDetail()?.contains(
                         "EmptyPatch"
                     ),
                     -> {
                         if (codeGenerationResultState.codeGenerationStatusDetail()?.contains("NO_CHANGE_REQUIRED") == true) {
-                            docServiceError(message("amazonqDoc.exception.no_change_required"))
+                            throw NoChangeRequiredException(
+                                operation = FeatureDevOperation.GenerateCode.toString(),
+                                desc = "No change required"
+                            )
                         }
-                        docServiceError(message("amazonqDoc.error_text"))
+                        throw EmptyPatchException(
+                            operation = FeatureDevOperation.GenerateCode.toString(),
+                            desc = "Empty patch"
+                        )
                     }
 
                     codeGenerationResultState.codeGenerationStatusDetail()?.contains(
                         "Throttling"
                     ),
-                    -> docServiceError(message("amazonqFeatureDev.exception.throttling"))
+                    -> throw ThrottlingException(
+                        operation = FeatureDevOperation.GenerateCode.toString(),
+                        desc = "Throttling occurred"
+                    )
 
-                    else -> docServiceError(message("amazonqDoc.error_text"))
+                    else -> throw DocGenerationException(operation = FeatureDevOperation.GenerateCode.toString(), desc = null)
                 }
             }
 
diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/session/DocSession.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/session/DocSession.kt
index f2d93be4bed..8e212e7f9a9 100644
--- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/session/DocSession.kt
+++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/session/DocSession.kt
@@ -24,8 +24,14 @@ import software.aws.toolkits.jetbrains.services.amazonq.messages.MessagePublishe
 import software.aws.toolkits.jetbrains.services.amazonqDoc.CODE_GENERATION_RETRY_LIMIT
 import software.aws.toolkits.jetbrains.services.amazonqDoc.FEATURE_NAME
 import software.aws.toolkits.jetbrains.services.amazonqDoc.MAX_PROJECT_SIZE_BYTES
-import software.aws.toolkits.jetbrains.services.amazonqDoc.conversationIdNotFound
+import software.aws.toolkits.jetbrains.services.amazonqDoc.MetricDataOperationName
+import software.aws.toolkits.jetbrains.services.amazonqDoc.MetricDataResult
 import software.aws.toolkits.jetbrains.services.amazonqDoc.messages.sendAsyncEventProgress
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.CLIENT_ERROR_MESSAGES
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ClientException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ConversationIdNotFoundException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.LlmException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ServiceException
 import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.DeletedFileInfo
 import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.Interaction
 import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.NewFileZipInfo
@@ -239,7 +245,7 @@ class DocSession(val tabID: String, val project: Project) {
     val conversationId: String
         get() {
             if (localConversationId == null) {
-                conversationIdNotFound()
+                throw ConversationIdNotFoundException(operation = "Session", desc = "Conversation ID not found")
             } else {
                 return localConversationId as String
             }
@@ -267,6 +273,19 @@ class DocSession(val tabID: String, val project: Project) {
         codegenRetries -= 1
     }
 
+    fun sendDocMetricData(operationName: MetricDataOperationName, result: MetricDataResult) {
+        val sendFeatureDevTelemetryEventResponse: SendTelemetryEventResponse
+        try {
+            sendFeatureDevTelemetryEventResponse = proxyClient.sendDocMetricData(operationName.toString(), result.toString())
+            val requestId = sendFeatureDevTelemetryEventResponse.responseMetadata().requestId()
+            logger.debug {
+                "${FEATURE_NAME}: succesfully sent doc metric data: OperationName: $operationName Result: $result RequestId: $requestId"
+            }
+        } catch (e: Exception) {
+            logger.warn(e) { "${FEATURE_NAME}:failed to send doc metric data" }
+        }
+    }
+
     fun sendDocTelemetryEvent(
         generationEvent: DocV2GenerationEvent? = null,
         acceptanceEvent: DocV2AcceptanceEvent? = null,
@@ -290,5 +309,33 @@ class DocSession(val tabID: String, val project: Project) {
         }
     }
 
+    fun getMetricResult(err: Exception): MetricDataResult {
+        val metricDataResult: MetricDataResult
+        when (err) {
+            is ClientException,
+            -> {
+                metricDataResult = MetricDataResult.Error
+            }
+
+            is LlmException -> {
+                metricDataResult = MetricDataResult.LlmFailure
+            }
+
+            is ServiceException -> {
+                metricDataResult = MetricDataResult.Fault
+            }
+
+            else -> {
+                val errorMessage = err.message.orEmpty()
+                metricDataResult = if (CLIENT_ERROR_MESSAGES.any { errorMessage.contains(it) }) {
+                    MetricDataResult.Error
+                } else {
+                    MetricDataResult.Fault
+                }
+            }
+        }
+        return metricDataResult
+    }
+
     fun getUserIdentity(): String = proxyClient.connection().id
 }


Reviews:
user: login: KevinDing1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T19:04:13Z
user: login: github-advanced-security[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-24T19:12:20Z
user: login: juanbenj
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T20:00:33Z
user: login: samgst-amazon
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T17:57:41Z

Review comments:
diff_hunk: @@ -626,12 +631,11 @@ class DocController(
             }
 
             is MonthlyConversationLimitError -> {
-                messenger.sendUpdatePlaceholder(tabId, newPlaceholder = message("amazonqFeatureDev.placeholder.after_monthly_limit"))
-                messenger.sendChatInputEnabledMessage(tabId, enabled = true)
                 messenger.sendMonthlyLimitError(tabId = tabId)
+                messenger.sendChatInputEnabledMessage(tabId, enabled = false)
path: plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/controller/DocController.kt
user: login: KevinDing1
body: This change is because we should handle the error as /dev did: https://github.com/aws/aws-toolkit-jetbrains/blob/42c1a99d766ea967269a7d26878eb7ac91aa6850/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/controller/FeatureDevController.kt#L628
created_at: 2025-03-24T19:02:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -3,24 +3,93 @@
 
 package software.aws.toolkits.jetbrains.services.amazonqDoc
 
+import software.aws.toolkits.jetbrains.services.amazonq.project.RepoSizeError
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ClientException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.LlmException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ServiceException
 import software.aws.toolkits.resources.message
 
-open class DocException(
-    override val message: String?,
-    override val cause: Throwable? = null,
+open class DocClientException(
+    message: String,
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
     val remainingIterations: Int? = null,
-) : RuntimeException()
+) : ClientException(message, operation, desc, cause)
 
-class ZipFileError(override val message: String, override val cause: Throwable?) : RuntimeException()
+val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
+fun createUserFacingErrorMessage(message: String?): String? =
+    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
 
-class CodeIterationLimitError(override val message: String, override val cause: Throwable?) : RuntimeException()
+class ReadmeTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_too_large"), operation, desc, cause, remainingIterations)
path: plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/DocExceptions.kt
user: login: github-advanced-security[bot]
body: ## Usage of redundant or deprecated syntax or deprecated symbols

'message(String, vararg Any): String' is deprecated. Use extension-specific localization bundle instead

[Show more details](https://github.com/aws/aws-toolkit-jetbrains/security/code-scanning/9653)
created_at: 2025-03-24T19:12:19Z
author_association: NONE
diff_hunk: @@ -3,24 +3,93 @@
 
 package software.aws.toolkits.jetbrains.services.amazonqDoc
 
+import software.aws.toolkits.jetbrains.services.amazonq.project.RepoSizeError
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ClientException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.LlmException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ServiceException
 import software.aws.toolkits.resources.message
 
-open class DocException(
-    override val message: String?,
-    override val cause: Throwable? = null,
+open class DocClientException(
+    message: String,
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
     val remainingIterations: Int? = null,
-) : RuntimeException()
+) : ClientException(message, operation, desc, cause)
 
-class ZipFileError(override val message: String, override val cause: Throwable?) : RuntimeException()
+val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
+fun createUserFacingErrorMessage(message: String?): String? =
+    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
 
-class CodeIterationLimitError(override val message: String, override val cause: Throwable?) : RuntimeException()
+class ReadmeTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun docServiceError(message: String?, cause: Throwable? = null, remainingIterations: Int? = null): Nothing =
-    throw DocException(message, cause, remainingIterations)
+class ReadmeUpdateTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_update_too_large"), operation, desc, cause, remainingIterations)
path: plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/DocExceptions.kt
user: login: github-advanced-security[bot]
body: ## Usage of redundant or deprecated syntax or deprecated symbols

'message(String, vararg Any): String' is deprecated. Use extension-specific localization bundle instead

[Show more details](https://github.com/aws/aws-toolkit-jetbrains/security/code-scanning/9661)
created_at: 2025-03-24T19:12:20Z
author_association: NONE
diff_hunk: @@ -3,24 +3,93 @@
 
 package software.aws.toolkits.jetbrains.services.amazonqDoc
 
+import software.aws.toolkits.jetbrains.services.amazonq.project.RepoSizeError
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ClientException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.LlmException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ServiceException
 import software.aws.toolkits.resources.message
 
-open class DocException(
-    override val message: String?,
-    override val cause: Throwable? = null,
+open class DocClientException(
+    message: String,
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
     val remainingIterations: Int? = null,
-) : RuntimeException()
+) : ClientException(message, operation, desc, cause)
 
-class ZipFileError(override val message: String, override val cause: Throwable?) : RuntimeException()
+val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
+fun createUserFacingErrorMessage(message: String?): String? =
+    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
 
-class CodeIterationLimitError(override val message: String, override val cause: Throwable?) : RuntimeException()
+class ReadmeTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun docServiceError(message: String?, cause: Throwable? = null, remainingIterations: Int? = null): Nothing =
-    throw DocException(message, cause, remainingIterations)
+class ReadmeUpdateTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_update_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun conversationIdNotFound(): Nothing =
-    throw DocException(message("amazonqFeatureDev.exception.conversation_not_found"))
+class ContentLengthException(
+    override val message: String = message("amazonqDoc.exception.content_length_error"),
path: plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/DocExceptions.kt
user: login: github-advanced-security[bot]
body: ## Usage of redundant or deprecated syntax or deprecated symbols

'message(String, vararg Any): String' is deprecated. Use extension-specific localization bundle instead

[Show more details](https://github.com/aws/aws-toolkit-jetbrains/security/code-scanning/9656)
created_at: 2025-03-24T19:12:20Z
author_association: NONE
diff_hunk: @@ -3,24 +3,93 @@
 
 package software.aws.toolkits.jetbrains.services.amazonqDoc
 
+import software.aws.toolkits.jetbrains.services.amazonq.project.RepoSizeError
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ClientException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.LlmException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ServiceException
 import software.aws.toolkits.resources.message
 
-open class DocException(
-    override val message: String?,
-    override val cause: Throwable? = null,
+open class DocClientException(
+    message: String,
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
     val remainingIterations: Int? = null,
-) : RuntimeException()
+) : ClientException(message, operation, desc, cause)
 
-class ZipFileError(override val message: String, override val cause: Throwable?) : RuntimeException()
+val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
+fun createUserFacingErrorMessage(message: String?): String? =
+    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
 
-class CodeIterationLimitError(override val message: String, override val cause: Throwable?) : RuntimeException()
+class ReadmeTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun docServiceError(message: String?, cause: Throwable? = null, remainingIterations: Int? = null): Nothing =
-    throw DocException(message, cause, remainingIterations)
+class ReadmeUpdateTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_update_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun conversationIdNotFound(): Nothing =
-    throw DocException(message("amazonqFeatureDev.exception.conversation_not_found"))
+class ContentLengthException(
+    override val message: String = message("amazonqDoc.exception.content_length_error"),
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) :
+    RepoSizeError, ClientException(message, operation, desc, cause)
 
-val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
-fun createUserFacingErrorMessage(message: String?): String? =
-    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
+class WorkspaceEmptyException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.exception.workspace_empty"), operation, desc, cause)
+
+class PromptUnrelatedException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.prompt_unrelated"), operation, desc, cause, remainingIterations)
path: plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/DocExceptions.kt
user: login: github-advanced-security[bot]
body: ## Usage of redundant or deprecated syntax or deprecated symbols

'message(String, vararg Any): String' is deprecated. Use extension-specific localization bundle instead

[Show more details](https://github.com/aws/aws-toolkit-jetbrains/security/code-scanning/9663)
created_at: 2025-03-24T19:12:20Z
author_association: NONE
diff_hunk: @@ -3,24 +3,93 @@
 
 package software.aws.toolkits.jetbrains.services.amazonqDoc
 
+import software.aws.toolkits.jetbrains.services.amazonq.project.RepoSizeError
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ClientException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.LlmException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ServiceException
 import software.aws.toolkits.resources.message
 
-open class DocException(
-    override val message: String?,
-    override val cause: Throwable? = null,
+open class DocClientException(
+    message: String,
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
     val remainingIterations: Int? = null,
-) : RuntimeException()
+) : ClientException(message, operation, desc, cause)
 
-class ZipFileError(override val message: String, override val cause: Throwable?) : RuntimeException()
+val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
+fun createUserFacingErrorMessage(message: String?): String? =
+    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
 
-class CodeIterationLimitError(override val message: String, override val cause: Throwable?) : RuntimeException()
+class ReadmeTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun docServiceError(message: String?, cause: Throwable? = null, remainingIterations: Int? = null): Nothing =
-    throw DocException(message, cause, remainingIterations)
+class ReadmeUpdateTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_update_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun conversationIdNotFound(): Nothing =
-    throw DocException(message("amazonqFeatureDev.exception.conversation_not_found"))
+class ContentLengthException(
+    override val message: String = message("amazonqDoc.exception.content_length_error"),
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) :
+    RepoSizeError, ClientException(message, operation, desc, cause)
 
-val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
-fun createUserFacingErrorMessage(message: String?): String? =
-    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
+class WorkspaceEmptyException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.exception.workspace_empty"), operation, desc, cause)
+
+class PromptUnrelatedException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.prompt_unrelated"), operation, desc, cause, remainingIterations)
+
+class PromptTooVagueException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.prompt_too_vague"), operation, desc, cause, remainingIterations)
path: plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/DocExceptions.kt
user: login: github-advanced-security[bot]
body: ## Usage of redundant or deprecated syntax or deprecated symbols

'message(String, vararg Any): String' is deprecated. Use extension-specific localization bundle instead

[Show more details](https://github.com/aws/aws-toolkit-jetbrains/security/code-scanning/9655)
created_at: 2025-03-24T19:12:20Z
author_association: NONE
diff_hunk: @@ -3,24 +3,93 @@
 
 package software.aws.toolkits.jetbrains.services.amazonqDoc
 
+import software.aws.toolkits.jetbrains.services.amazonq.project.RepoSizeError
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ClientException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.LlmException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ServiceException
 import software.aws.toolkits.resources.message
 
-open class DocException(
-    override val message: String?,
-    override val cause: Throwable? = null,
+open class DocClientException(
+    message: String,
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
     val remainingIterations: Int? = null,
-) : RuntimeException()
+) : ClientException(message, operation, desc, cause)
 
-class ZipFileError(override val message: String, override val cause: Throwable?) : RuntimeException()
+val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
+fun createUserFacingErrorMessage(message: String?): String? =
+    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
 
-class CodeIterationLimitError(override val message: String, override val cause: Throwable?) : RuntimeException()
+class ReadmeTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun docServiceError(message: String?, cause: Throwable? = null, remainingIterations: Int? = null): Nothing =
-    throw DocException(message, cause, remainingIterations)
+class ReadmeUpdateTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_update_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun conversationIdNotFound(): Nothing =
-    throw DocException(message("amazonqFeatureDev.exception.conversation_not_found"))
+class ContentLengthException(
+    override val message: String = message("amazonqDoc.exception.content_length_error"),
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) :
+    RepoSizeError, ClientException(message, operation, desc, cause)
 
-val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
-fun createUserFacingErrorMessage(message: String?): String? =
-    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
+class WorkspaceEmptyException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.exception.workspace_empty"), operation, desc, cause)
+
+class PromptUnrelatedException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.prompt_unrelated"), operation, desc, cause, remainingIterations)
+
+class PromptTooVagueException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.prompt_too_vague"), operation, desc, cause, remainingIterations)
+
+class PromptRefusalException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqFeatureDev.exception.prompt_refusal"), operation, desc, cause, remainingIterations)
path: plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/DocExceptions.kt
user: login: github-advanced-security[bot]
body: ## Usage of redundant or deprecated syntax or deprecated symbols

'message(String, vararg Any): String' is deprecated. Use extension-specific localization bundle instead

[Show more details](https://github.com/aws/aws-toolkit-jetbrains/security/code-scanning/9660)
created_at: 2025-03-24T19:12:20Z
author_association: NONE
diff_hunk: @@ -3,24 +3,93 @@
 
 package software.aws.toolkits.jetbrains.services.amazonqDoc
 
+import software.aws.toolkits.jetbrains.services.amazonq.project.RepoSizeError
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ClientException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.LlmException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ServiceException
 import software.aws.toolkits.resources.message
 
-open class DocException(
-    override val message: String?,
-    override val cause: Throwable? = null,
+open class DocClientException(
+    message: String,
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
     val remainingIterations: Int? = null,
-) : RuntimeException()
+) : ClientException(message, operation, desc, cause)
 
-class ZipFileError(override val message: String, override val cause: Throwable?) : RuntimeException()
+val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
+fun createUserFacingErrorMessage(message: String?): String? =
+    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
 
-class CodeIterationLimitError(override val message: String, override val cause: Throwable?) : RuntimeException()
+class ReadmeTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun docServiceError(message: String?, cause: Throwable? = null, remainingIterations: Int? = null): Nothing =
-    throw DocException(message, cause, remainingIterations)
+class ReadmeUpdateTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_update_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun conversationIdNotFound(): Nothing =
-    throw DocException(message("amazonqFeatureDev.exception.conversation_not_found"))
+class ContentLengthException(
+    override val message: String = message("amazonqDoc.exception.content_length_error"),
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) :
+    RepoSizeError, ClientException(message, operation, desc, cause)
 
-val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
-fun createUserFacingErrorMessage(message: String?): String? =
-    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
+class WorkspaceEmptyException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.exception.workspace_empty"), operation, desc, cause)
+
+class PromptUnrelatedException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.prompt_unrelated"), operation, desc, cause, remainingIterations)
+
+class PromptTooVagueException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.prompt_too_vague"), operation, desc, cause, remainingIterations)
+
+class PromptRefusalException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqFeatureDev.exception.prompt_refusal"), operation, desc, cause, remainingIterations)
+
+class GuardrailsException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.error_text"), operation, desc, cause)
path: plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/DocExceptions.kt
user: login: github-advanced-security[bot]
body: ## Usage of redundant or deprecated syntax or deprecated symbols

'message(String, vararg Any): String' is deprecated. Use extension-specific localization bundle instead

[Show more details](https://github.com/aws/aws-toolkit-jetbrains/security/code-scanning/9658)
created_at: 2025-03-24T19:12:20Z
author_association: NONE
diff_hunk: @@ -3,24 +3,93 @@
 
 package software.aws.toolkits.jetbrains.services.amazonqDoc
 
+import software.aws.toolkits.jetbrains.services.amazonq.project.RepoSizeError
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ClientException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.LlmException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ServiceException
 import software.aws.toolkits.resources.message
 
-open class DocException(
-    override val message: String?,
-    override val cause: Throwable? = null,
+open class DocClientException(
+    message: String,
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
     val remainingIterations: Int? = null,
-) : RuntimeException()
+) : ClientException(message, operation, desc, cause)
 
-class ZipFileError(override val message: String, override val cause: Throwable?) : RuntimeException()
+val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
+fun createUserFacingErrorMessage(message: String?): String? =
+    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
 
-class CodeIterationLimitError(override val message: String, override val cause: Throwable?) : RuntimeException()
+class ReadmeTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun docServiceError(message: String?, cause: Throwable? = null, remainingIterations: Int? = null): Nothing =
-    throw DocException(message, cause, remainingIterations)
+class ReadmeUpdateTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_update_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun conversationIdNotFound(): Nothing =
-    throw DocException(message("amazonqFeatureDev.exception.conversation_not_found"))
+class ContentLengthException(
+    override val message: String = message("amazonqDoc.exception.content_length_error"),
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) :
+    RepoSizeError, ClientException(message, operation, desc, cause)
 
-val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
-fun createUserFacingErrorMessage(message: String?): String? =
-    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
+class WorkspaceEmptyException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.exception.workspace_empty"), operation, desc, cause)
+
+class PromptUnrelatedException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.prompt_unrelated"), operation, desc, cause, remainingIterations)
+
+class PromptTooVagueException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.prompt_too_vague"), operation, desc, cause, remainingIterations)
+
+class PromptRefusalException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqFeatureDev.exception.prompt_refusal"), operation, desc, cause, remainingIterations)
+
+class GuardrailsException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.error_text"), operation, desc, cause)
+
+class NoChangeRequiredException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.exception.no_change_required"), operation, desc, cause)
path: plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/DocExceptions.kt
user: login: github-advanced-security[bot]
body: ## Usage of redundant or deprecated syntax or deprecated symbols

'message(String, vararg Any): String' is deprecated. Use extension-specific localization bundle instead

[Show more details](https://github.com/aws/aws-toolkit-jetbrains/security/code-scanning/9654)
created_at: 2025-03-24T19:12:20Z
author_association: NONE
diff_hunk: @@ -3,24 +3,93 @@
 
 package software.aws.toolkits.jetbrains.services.amazonqDoc
 
+import software.aws.toolkits.jetbrains.services.amazonq.project.RepoSizeError
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ClientException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.LlmException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ServiceException
 import software.aws.toolkits.resources.message
 
-open class DocException(
-    override val message: String?,
-    override val cause: Throwable? = null,
+open class DocClientException(
+    message: String,
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
     val remainingIterations: Int? = null,
-) : RuntimeException()
+) : ClientException(message, operation, desc, cause)
 
-class ZipFileError(override val message: String, override val cause: Throwable?) : RuntimeException()
+val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
+fun createUserFacingErrorMessage(message: String?): String? =
+    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
 
-class CodeIterationLimitError(override val message: String, override val cause: Throwable?) : RuntimeException()
+class ReadmeTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun docServiceError(message: String?, cause: Throwable? = null, remainingIterations: Int? = null): Nothing =
-    throw DocException(message, cause, remainingIterations)
+class ReadmeUpdateTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_update_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun conversationIdNotFound(): Nothing =
-    throw DocException(message("amazonqFeatureDev.exception.conversation_not_found"))
+class ContentLengthException(
+    override val message: String = message("amazonqDoc.exception.content_length_error"),
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) :
+    RepoSizeError, ClientException(message, operation, desc, cause)
 
-val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
-fun createUserFacingErrorMessage(message: String?): String? =
-    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
+class WorkspaceEmptyException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.exception.workspace_empty"), operation, desc, cause)
+
+class PromptUnrelatedException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.prompt_unrelated"), operation, desc, cause, remainingIterations)
+
+class PromptTooVagueException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.prompt_too_vague"), operation, desc, cause, remainingIterations)
+
+class PromptRefusalException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqFeatureDev.exception.prompt_refusal"), operation, desc, cause, remainingIterations)
+
+class GuardrailsException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.error_text"), operation, desc, cause)
+
+class NoChangeRequiredException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.exception.no_change_required"), operation, desc, cause)
+
+class EmptyPatchException(operation: String, desc: String?, cause: Throwable? = null) :
+    LlmException(message("amazonqDoc.error_text"), operation, desc, cause)
path: plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/DocExceptions.kt
user: login: github-advanced-security[bot]
body: ## Usage of redundant or deprecated syntax or deprecated symbols

'message(String, vararg Any): String' is deprecated. Use extension-specific localization bundle instead

[Show more details](https://github.com/aws/aws-toolkit-jetbrains/security/code-scanning/9659)
created_at: 2025-03-24T19:12:20Z
author_association: NONE
diff_hunk: @@ -3,24 +3,93 @@
 
 package software.aws.toolkits.jetbrains.services.amazonqDoc
 
+import software.aws.toolkits.jetbrains.services.amazonq.project.RepoSizeError
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ClientException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.LlmException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ServiceException
 import software.aws.toolkits.resources.message
 
-open class DocException(
-    override val message: String?,
-    override val cause: Throwable? = null,
+open class DocClientException(
+    message: String,
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
     val remainingIterations: Int? = null,
-) : RuntimeException()
+) : ClientException(message, operation, desc, cause)
 
-class ZipFileError(override val message: String, override val cause: Throwable?) : RuntimeException()
+val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
+fun createUserFacingErrorMessage(message: String?): String? =
+    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
 
-class CodeIterationLimitError(override val message: String, override val cause: Throwable?) : RuntimeException()
+class ReadmeTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun docServiceError(message: String?, cause: Throwable? = null, remainingIterations: Int? = null): Nothing =
-    throw DocException(message, cause, remainingIterations)
+class ReadmeUpdateTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_update_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun conversationIdNotFound(): Nothing =
-    throw DocException(message("amazonqFeatureDev.exception.conversation_not_found"))
+class ContentLengthException(
+    override val message: String = message("amazonqDoc.exception.content_length_error"),
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) :
+    RepoSizeError, ClientException(message, operation, desc, cause)
 
-val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
-fun createUserFacingErrorMessage(message: String?): String? =
-    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
+class WorkspaceEmptyException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.exception.workspace_empty"), operation, desc, cause)
+
+class PromptUnrelatedException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.prompt_unrelated"), operation, desc, cause, remainingIterations)
+
+class PromptTooVagueException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.prompt_too_vague"), operation, desc, cause, remainingIterations)
+
+class PromptRefusalException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqFeatureDev.exception.prompt_refusal"), operation, desc, cause, remainingIterations)
+
+class GuardrailsException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.error_text"), operation, desc, cause)
+
+class NoChangeRequiredException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.exception.no_change_required"), operation, desc, cause)
+
+class EmptyPatchException(operation: String, desc: String?, cause: Throwable? = null) :
+    LlmException(message("amazonqDoc.error_text"), operation, desc, cause)
+
+class ThrottlingException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqFeatureDev.exception.throttling"), operation, desc, cause)
path: plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/DocExceptions.kt
user: login: github-advanced-security[bot]
body: ## Usage of redundant or deprecated syntax or deprecated symbols

'message(String, vararg Any): String' is deprecated. Use extension-specific localization bundle instead

[Show more details](https://github.com/aws/aws-toolkit-jetbrains/security/code-scanning/9657)
created_at: 2025-03-24T19:12:20Z
author_association: NONE
diff_hunk: @@ -3,24 +3,93 @@
 
 package software.aws.toolkits.jetbrains.services.amazonqDoc
 
+import software.aws.toolkits.jetbrains.services.amazonq.project.RepoSizeError
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ClientException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.LlmException
+import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ServiceException
 import software.aws.toolkits.resources.message
 
-open class DocException(
-    override val message: String?,
-    override val cause: Throwable? = null,
+open class DocClientException(
+    message: String,
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
     val remainingIterations: Int? = null,
-) : RuntimeException()
+) : ClientException(message, operation, desc, cause)
 
-class ZipFileError(override val message: String, override val cause: Throwable?) : RuntimeException()
+val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
+fun createUserFacingErrorMessage(message: String?): String? =
+    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
 
-class CodeIterationLimitError(override val message: String, override val cause: Throwable?) : RuntimeException()
+class ReadmeTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun docServiceError(message: String?, cause: Throwable? = null, remainingIterations: Int? = null): Nothing =
-    throw DocException(message, cause, remainingIterations)
+class ReadmeUpdateTooLargeException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.readme_update_too_large"), operation, desc, cause, remainingIterations)
 
-internal fun conversationIdNotFound(): Nothing =
-    throw DocException(message("amazonqFeatureDev.exception.conversation_not_found"))
+class ContentLengthException(
+    override val message: String = message("amazonqDoc.exception.content_length_error"),
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) :
+    RepoSizeError, ClientException(message, operation, desc, cause)
 
-val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
-fun createUserFacingErrorMessage(message: String?): String? =
-    if (message != null && denyListedErrors.any { message.contains(it) }) "$FEATURE_NAME API request failed" else message
+class WorkspaceEmptyException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.exception.workspace_empty"), operation, desc, cause)
+
+class PromptUnrelatedException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.prompt_unrelated"), operation, desc, cause, remainingIterations)
+
+class PromptTooVagueException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqDoc.exception.prompt_too_vague"), operation, desc, cause, remainingIterations)
+
+class PromptRefusalException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+    remainingIterations: Int? = null,
+) : DocClientException(message("amazonqFeatureDev.exception.prompt_refusal"), operation, desc, cause, remainingIterations)
+
+class GuardrailsException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.error_text"), operation, desc, cause)
+
+class NoChangeRequiredException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqDoc.exception.no_change_required"), operation, desc, cause)
+
+class EmptyPatchException(operation: String, desc: String?, cause: Throwable? = null) :
+    LlmException(message("amazonqDoc.error_text"), operation, desc, cause)
+
+class ThrottlingException(
+    operation: String,
+    desc: String?,
+    cause: Throwable? = null,
+) : DocClientException(message("amazonqFeatureDev.exception.throttling"), operation, desc, cause)
+
+class DocGenerationException(operation: String, desc: String?, cause: Throwable? = null) :
+    ServiceException(message("amazonqDoc.error_text"), operation, desc, cause)
path: plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqDoc/DocExceptions.kt
user: login: github-advanced-security[bot]
body: ## Usage of redundant or deprecated syntax or deprecated symbols

'message(String, vararg Any): String' is deprecated. Use extension-specific localization bundle instead

[Show more details](https://github.com/aws/aws-toolkit-jetbrains/security/code-scanning/9662)
created_at: 2025-03-24T19:12:20Z
author_association: NONE

PR comments:
user: login: KevinDing1
created_at: 2025-03-24T19:48:19Z
body: /retryBuilds
author_association: CONTRIBUTOR
user: login: KevinDing1
created_at: 2025-03-31T14:37:47Z
body: /retryBuilds
author_association: CONTRIBUTOR
user: login: KevinDing1
created_at: 2025-03-31T16:33:24Z
body: /retryBuilds
author_association: CONTRIBUTOR
user: login: samgst-amazon
created_at: 2025-03-31T20:50:32Z
body: /retryBuilds

author_association: CONTRIBUTOR