diff --git a/skyvern-frontend/src/routes/workflows/editor/panels/WorkflowParameterAddPanel.tsx b/skyvern-frontend/src/routes/workflows/editor/panels/WorkflowParameterAddPanel.tsx
index ad686a61..76ebc9d3 100644
--- a/skyvern-frontend/src/routes/workflows/editor/panels/WorkflowParameterAddPanel.tsx
+++ b/skyvern-frontend/src/routes/workflows/editor/panels/WorkflowParameterAddPanel.tsx
@@ -61,6 +61,7 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
const reservedKeys = ["current_item", "current_value", "current_index"];
const isCloud = useContext(CloudContext);
const [key, setKey] = useState("");
+ const hasWhitespace = /\s/.test(key);
const [urlParameterKey, setUrlParameterKey] = useState("");
const [description, setDescription] = useState("");
const [bitwardenCollectionId, setBitwardenCollectionId] = useState("");
@@ -108,6 +109,11 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
setKey(e.target.value)} />
+ {hasWhitespace && (
+
+ Spaces are not allowed, consider using _
+
+ )}
@@ -398,6 +404,14 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
});
return;
}
+ if (hasWhitespace) {
+ toast({
+ variant: "destructive",
+ title: "Failed to add parameter",
+ description: "Key cannot contain whitespaces",
+ });
+ return;
+ }
if (reservedKeys.includes(key)) {
toast({
variant: "destructive",
diff --git a/skyvern-frontend/src/routes/workflows/editor/panels/WorkflowParameterEditPanel.tsx b/skyvern-frontend/src/routes/workflows/editor/panels/WorkflowParameterEditPanel.tsx
index 0034cc20..0d636ac4 100644
--- a/skyvern-frontend/src/routes/workflows/editor/panels/WorkflowParameterEditPanel.tsx
+++ b/skyvern-frontend/src/routes/workflows/editor/panels/WorkflowParameterEditPanel.tsx
@@ -73,6 +73,7 @@ function WorkflowParameterEditPanel({
}: Props) {
const isCloud = useContext(CloudContext);
const [key, setKey] = useState(initialValues.key);
+ const hasWhitespace = /\s/.test(key);
const isBitwardenCredential =
initialValues.parameterType === "credential" &&
parameterIsBitwardenCredential(initialValues);
@@ -192,6 +193,11 @@ function WorkflowParameterEditPanel({
setKey(e.target.value)} />
+ {hasWhitespace && (
+
+ Spaces are not allowed, consider using _
+
+ )}
@@ -480,6 +486,15 @@ function WorkflowParameterEditPanel({
});
return;
}
+ if (hasWhitespace) {
+ toast({
+ variant: "destructive",
+ title: "Failed to save parameter",
+ description:
+ "Key cannot contain whitespace characters. Consider using underscores (_) instead.",
+ });
+ return;
+ }
if (type === "workflow") {
if (
parameterType === "json" &&
diff --git a/skyvern/schemas/workflows.py b/skyvern/schemas/workflows.py
index 8d95c6f0..1c6b0a56 100644
--- a/skyvern/schemas/workflows.py
+++ b/skyvern/schemas/workflows.py
@@ -3,7 +3,7 @@ from dataclasses import dataclass
from enum import StrEnum
from typing import Annotated, Any, Literal
-from pydantic import BaseModel, Field
+from pydantic import BaseModel, Field, field_validator
from skyvern.config import settings
from skyvern.forge.sdk.workflow.models.parameter import OutputParameter, ParameterType, WorkflowParameterType
@@ -74,6 +74,13 @@ class ParameterYAML(BaseModel, abc.ABC):
key: str
description: str | None = None
+ @field_validator("key")
+ @classmethod
+ def validate_no_whitespace(cls, v: str) -> str:
+ if any(char in v for char in [" ", "\t", "\n", "\r"]):
+ raise ValueError("Key cannot contain whitespaces")
+ return v
+
class AWSSecretParameterYAML(ParameterYAML):
# There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: