@@ -539,6 +539,23 @@ def normalize_vertex_ai_model_id(model_id: str) -> str:
539539 return model_id
540540
541541
542+ def is_resource_exhausted_error (error_message : str ) -> bool :
543+ """Detect Vertex AI RESOURCE_EXHAUSTED errors wrapped as 500 by llama-stack.
544+
545+ llama-stack's remote::vertexai provider translates Vertex AI's 429
546+ RESOURCE_EXHAUSTED into a generic 500 InternalServerError, losing the
547+ original status code. The original gRPC status name is preserved in
548+ the error message, so we match on that.
549+
550+ Args:
551+ error_message: The error message to inspect.
552+
553+ Returns:
554+ True if the message indicates a wrapped RESOURCE_EXHAUSTED error.
555+ """
556+ return "resource_exhausted" in error_message .lower ()
557+
558+
542559def handle_known_apistatus_errors (
543560 error : LLSApiStatusError | OpenAIAPIStatusError , model_id : str
544561) -> AbstractErrorResponse :
@@ -556,4 +573,11 @@ def handle_known_apistatus_errors(
556573 return PromptTooLongResponse (model = model_id )
557574 if error .status_code == 429 :
558575 return QuotaExceededResponse .model (model_id )
576+ if is_resource_exhausted_error (error_message ):
577+ logger .warning (
578+ "Detected RESOURCE_EXHAUSTED in error message with status %d; "
579+ "treating as 429 (llama-stack wraps Vertex AI 429 as 500)" ,
580+ error .status_code ,
581+ )
582+ return QuotaExceededResponse .model (model_id )
559583 return InternalServerErrorResponse .generic ()
0 commit comments