Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
fix: address review feedback on validation logic
- Allow single-block workflows to run (blockCount > 1 check instead of
  hasBlocks && !hasEdges, which incorrectly blocked standalone blocks)
- Guard Mod+Enter keyboard shortcut with isButtonDisabled to match Run
  button behavior and prevent bypassing validation
- Add explicit variables: {} default in deploy route to avoid relying on
  type assertion to paper over a missing field

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
  • Loading branch information
MaxwellCalkin and claude committed Mar 9, 2026
commit 2766a3963b115329266d5915c6239cac217bc651
1 change: 1 addition & 0 deletions apps/sim/app/api/workflows/[id]/deploy/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
edges: normalizedData.edges,
loops: normalizedData.loops,
parallels: normalizedData.parallels,
variables: {},
} as WorkflowState)
Comment on lines +139 to +145
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type assertion papers over a missing variables field

normalizedData may not include a variables property, so the cast as WorkflowState silently satisfies TypeScript while potentially producing undefined at runtime for that field. validateWorkflowState only uses blocks and edges, but if the function signature ever evolves, this cast could hide a real gap.

Consider spreading a safe default instead:

Suggested change
const workflowValidation = validateWorkflowState({
blocks: normalizedData.blocks,
edges: normalizedData.edges,
loops: normalizedData.loops,
parallels: normalizedData.parallels,
} as WorkflowState)
const workflowValidation = validateWorkflowState({
blocks: normalizedData.blocks,
edges: normalizedData.edges,
loops: normalizedData.loops,
parallels: normalizedData.parallels,
variables: {},
} as WorkflowState)

if (!workflowValidation.valid) {
const errorSummary = workflowValidation.errors.join('; ')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,9 +357,12 @@ export const Panel = memo(function Panel() {
const canRun = userPermissions.canRead // Running only requires read permissions
const isLoadingPermissions = userPermissions.isLoading

// Validate workflow has connected blocks (at least one edge means blocks are wired together)
// Validate workflow has connected blocks when multiple blocks exist.
// A single-block workflow (e.g. one starter or agent block) is valid without edges,
// but multiple blocks with no edges indicates a disconnected graph.
const blockCount = useWorkflowStore((state) => Object.keys(state.blocks).length)
const hasEdges = useWorkflowStore((state) => state.edges.length > 0)
const hasValidationErrors = hasBlocks && !hasEdges
const hasValidationErrors = blockCount > 1 && !hasEdges

Comment thread
cursor[bot] marked this conversation as resolved.
const isWorkflowBlocked = isExecuting || hasValidationErrors
const isButtonDisabled = !isExecuting && (isWorkflowBlocked || (!canRun && !isLoadingPermissions))
Expand All @@ -377,7 +380,7 @@ export const Panel = memo(function Panel() {
handler: () => {
if (isExecuting) {
void cancelWorkflow()
} else {
} else if (!isButtonDisabled) {
void runWorkflow()
}
},
Expand Down