diff --git a/skyvern/forge/sdk/routes/agent_protocol.py b/skyvern/forge/sdk/routes/agent_protocol.py index 0add3b12..8d34c4ae 100644 --- a/skyvern/forge/sdk/routes/agent_protocol.py +++ b/skyvern/forge/sdk/routes/agent_protocol.py @@ -18,11 +18,16 @@ from fastapi import ( ) from fastapi import status as http_status from fastapi.responses import ORJSONResponse +from pydantic import ValidationError from skyvern import analytics from skyvern._version import __version__ from skyvern.config import settings -from skyvern.exceptions import CannotUpdateWorkflowDueToCodeCache, MissingBrowserAddressError +from skyvern.exceptions import ( + CannotUpdateWorkflowDueToCodeCache, + MissingBrowserAddressError, + SkyvernHTTPException, +) from skyvern.forge import app from skyvern.forge.prompts import prompt_engine from skyvern.forge.sdk.api.llm.exceptions import LLMProviderError @@ -826,6 +831,9 @@ async def update_workflow_legacy( ) from e except WorkflowParameterMissingRequiredValue as e: raise e + except (SkyvernHTTPException, ValidationError) as e: + # Bubble up well-formed client errors so they are not converted to 500s + raise e except Exception as e: LOG.exception( "Failed to update workflow", @@ -897,6 +905,9 @@ async def update_workflow( raise HTTPException(status_code=422, detail="Invalid YAML") except WorkflowParameterMissingRequiredValue as e: raise e + except (SkyvernHTTPException, ValidationError) as e: + # Bubble up well-formed client errors so they are not converted to 500s + raise e except Exception as e: LOG.exception( "Failed to update workflow", diff --git a/skyvern/forge/sdk/workflow/service.py b/skyvern/forge/sdk/workflow/service.py index 2ce0a083..36c9338a 100644 --- a/skyvern/forge/sdk/workflow/service.py +++ b/skyvern/forge/sdk/workflow/service.py @@ -3339,7 +3339,9 @@ class WorkflowService: loop_over_parameter = parameters[trimmed_key] if loop_over_parameter is None and not block_yaml.loop_variable_reference: - raise Exception("Loop value parameter is required for for loop block") + raise InvalidWorkflowDefinition( + f"For loop block '{block_yaml.label}' requires either loop_over_parameter_key or loop_variable_reference" + ) return ForLoopBlock( **base_kwargs, @@ -3458,7 +3460,9 @@ class WorkflowService: ) if not block_yaml.complete_criterion and not block_yaml.terminate_criterion: - raise Exception("Both complete criterion and terminate criterion are empty") + raise InvalidWorkflowDefinition( + f"Validation block '{block_yaml.label}' requires at least one of complete_criterion or terminate_criterion" + ) return ValidationBlock( **base_kwargs, @@ -3479,7 +3483,7 @@ class WorkflowService: ) if not block_yaml.navigation_goal: - raise Exception("empty action instruction") + raise InvalidWorkflowDefinition(f"Action block '{block_yaml.label}' requires navigation_goal") return ActionBlock( **base_kwargs,