From d0d35dd4067d45c5ba9e873b4603e67f8709048b Mon Sep 17 00:00:00 2001 From: Waleed Date: Wed, 8 Apr 2026 00:26:33 -0700 Subject: [PATCH] fix: address PR review comments (#4042) * fix: address PR review comments on staging release - Add try/catch around clipboard.writeText() in CopyCodeButton - Add missing folder and past_chat cases in resolveResourceFromContext - Return 400 for ZodError instead of 500 in all 8 Athena API routes Co-Authored-By: Claude Opus 4.6 * fix(api): return 400 for Zod validation errors across 27 API routes Routes using z.parse() were returning 500 for ZodError (client input validation failures). Added instanceof z.ZodError check to return 400 before the generic 500 handler, matching the established pattern used by 115+ other routes. Affected services: CloudWatch (7), CloudFormation (7), DynamoDB (6), Slack (3), Outlook (2), OneDrive (1), Google Drive (1). Co-Authored-By: Claude Opus 4.6 * fix(api): add success:false to ZodError responses for consistency 7 routes used { success: false, error: ... } in their generic error handler but our ZodError handler only returned { error: ... }. Aligned the ZodError response shape to match. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 --- .../app/api/tools/athena/create-named-query/route.ts | 6 ++++++ .../app/api/tools/athena/get-named-query/route.ts | 6 ++++++ .../api/tools/athena/get-query-execution/route.ts | 6 ++++++ .../app/api/tools/athena/get-query-results/route.ts | 6 ++++++ .../app/api/tools/athena/list-named-queries/route.ts | 6 ++++++ .../api/tools/athena/list-query-executions/route.ts | 6 ++++++ apps/sim/app/api/tools/athena/start-query/route.ts | 6 ++++++ apps/sim/app/api/tools/athena/stop-query/route.ts | 6 ++++++ .../describe-stack-drift-detection-status/route.ts | 6 ++++++ .../cloudformation/describe-stack-events/route.ts | 6 ++++++ .../tools/cloudformation/describe-stacks/route.ts | 6 ++++++ .../tools/cloudformation/detect-stack-drift/route.ts | 6 ++++++ .../api/tools/cloudformation/get-template/route.ts | 6 ++++++ .../cloudformation/list-stack-resources/route.ts | 6 ++++++ .../tools/cloudformation/validate-template/route.ts | 6 ++++++ .../api/tools/cloudwatch/describe-alarms/route.ts | 6 ++++++ .../tools/cloudwatch/describe-log-groups/route.ts | 6 ++++++ .../tools/cloudwatch/describe-log-streams/route.ts | 6 ++++++ .../app/api/tools/cloudwatch/get-log-events/route.ts | 6 ++++++ .../tools/cloudwatch/get-metric-statistics/route.ts | 6 ++++++ .../app/api/tools/cloudwatch/list-metrics/route.ts | 6 ++++++ .../sim/app/api/tools/cloudwatch/query-logs/route.ts | 6 ++++++ apps/sim/app/api/tools/dynamodb/delete/route.ts | 6 ++++++ apps/sim/app/api/tools/dynamodb/get/route.ts | 6 ++++++ apps/sim/app/api/tools/dynamodb/put/route.ts | 6 ++++++ apps/sim/app/api/tools/dynamodb/query/route.ts | 6 ++++++ apps/sim/app/api/tools/dynamodb/scan/route.ts | 6 ++++++ apps/sim/app/api/tools/dynamodb/update/route.ts | 6 ++++++ .../sim/app/api/tools/google_drive/download/route.ts | 6 ++++++ apps/sim/app/api/tools/onedrive/download/route.ts | 6 ++++++ apps/sim/app/api/tools/outlook/draft/route.ts | 6 ++++++ apps/sim/app/api/tools/outlook/send/route.ts | 6 ++++++ apps/sim/app/api/tools/slack/download/route.ts | 6 ++++++ apps/sim/app/api/tools/slack/send-ephemeral/route.ts | 6 ++++++ apps/sim/app/api/tools/slack/send-message/route.ts | 6 ++++++ apps/sim/components/ui/copy-code-button.tsx | 12 ++++++++---- 36 files changed, 218 insertions(+), 4 deletions(-) diff --git a/apps/sim/app/api/tools/athena/create-named-query/route.ts b/apps/sim/app/api/tools/athena/create-named-query/route.ts index f9f997d618..f49bc16247 100644 --- a/apps/sim/app/api/tools/athena/create-named-query/route.ts +++ b/apps/sim/app/api/tools/athena/create-named-query/route.ts @@ -55,6 +55,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to create Athena named query' logger.error('CreateNamedQuery failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/athena/get-named-query/route.ts b/apps/sim/app/api/tools/athena/get-named-query/route.ts index 83e9845b75..394bbda2b8 100644 --- a/apps/sim/app/api/tools/athena/get-named-query/route.ts +++ b/apps/sim/app/api/tools/athena/get-named-query/route.ts @@ -53,6 +53,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to get Athena named query' logger.error('GetNamedQuery failed', { error: errorMessage }) return NextResponse.json({ error: errorMessage }, { status: 500 }) diff --git a/apps/sim/app/api/tools/athena/get-query-execution/route.ts b/apps/sim/app/api/tools/athena/get-query-execution/route.ts index b043db1141..129f4794dc 100644 --- a/apps/sim/app/api/tools/athena/get-query-execution/route.ts +++ b/apps/sim/app/api/tools/athena/get-query-execution/route.ts @@ -63,6 +63,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to get Athena query execution' logger.error('GetQueryExecution failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/athena/get-query-results/route.ts b/apps/sim/app/api/tools/athena/get-query-results/route.ts index d89488371d..260cc73dc0 100644 --- a/apps/sim/app/api/tools/athena/get-query-results/route.ts +++ b/apps/sim/app/api/tools/athena/get-query-results/route.ts @@ -74,6 +74,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to get Athena query results' logger.error('GetQueryResults failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/athena/list-named-queries/route.ts b/apps/sim/app/api/tools/athena/list-named-queries/route.ts index c9f74ca216..326e03711b 100644 --- a/apps/sim/app/api/tools/athena/list-named-queries/route.ts +++ b/apps/sim/app/api/tools/athena/list-named-queries/route.ts @@ -51,6 +51,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to list Athena named queries' logger.error('ListNamedQueries failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/athena/list-query-executions/route.ts b/apps/sim/app/api/tools/athena/list-query-executions/route.ts index 096afee99c..958d09b173 100644 --- a/apps/sim/app/api/tools/athena/list-query-executions/route.ts +++ b/apps/sim/app/api/tools/athena/list-query-executions/route.ts @@ -51,6 +51,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to list Athena query executions' logger.error('ListQueryExecutions failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/athena/start-query/route.ts b/apps/sim/app/api/tools/athena/start-query/route.ts index 6af793cbe0..0555246aa8 100644 --- a/apps/sim/app/api/tools/athena/start-query/route.ts +++ b/apps/sim/app/api/tools/athena/start-query/route.ts @@ -67,6 +67,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to start Athena query' logger.error('StartQuery failed', { error: errorMessage }) return NextResponse.json({ error: errorMessage }, { status: 500 }) diff --git a/apps/sim/app/api/tools/athena/stop-query/route.ts b/apps/sim/app/api/tools/athena/stop-query/route.ts index 2f3422b36e..0a7558d314 100644 --- a/apps/sim/app/api/tools/athena/stop-query/route.ts +++ b/apps/sim/app/api/tools/athena/stop-query/route.ts @@ -43,6 +43,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to stop Athena query' logger.error('StopQuery failed', { error: errorMessage }) return NextResponse.json({ error: errorMessage }, { status: 500 }) diff --git a/apps/sim/app/api/tools/cloudformation/describe-stack-drift-detection-status/route.ts b/apps/sim/app/api/tools/cloudformation/describe-stack-drift-detection-status/route.ts index b47611b0cf..d267bb01fa 100644 --- a/apps/sim/app/api/tools/cloudformation/describe-stack-drift-detection-status/route.ts +++ b/apps/sim/app/api/tools/cloudformation/describe-stack-drift-detection-status/route.ts @@ -53,6 +53,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to describe stack drift detection status' logger.error('DescribeStackDriftDetectionStatus failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudformation/describe-stack-events/route.ts b/apps/sim/app/api/tools/cloudformation/describe-stack-events/route.ts index b838512a43..a3108eebff 100644 --- a/apps/sim/app/api/tools/cloudformation/describe-stack-events/route.ts +++ b/apps/sim/app/api/tools/cloudformation/describe-stack-events/route.ts @@ -70,6 +70,12 @@ export async function POST(request: NextRequest) { output: { events }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to describe CloudFormation stack events' logger.error('DescribeStackEvents failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudformation/describe-stacks/route.ts b/apps/sim/app/api/tools/cloudformation/describe-stacks/route.ts index 30cf207d7e..d8fc946b51 100644 --- a/apps/sim/app/api/tools/cloudformation/describe-stacks/route.ts +++ b/apps/sim/app/api/tools/cloudformation/describe-stacks/route.ts @@ -78,6 +78,12 @@ export async function POST(request: NextRequest) { output: { stacks }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to describe CloudFormation stacks' logger.error('DescribeStacks failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudformation/detect-stack-drift/route.ts b/apps/sim/app/api/tools/cloudformation/detect-stack-drift/route.ts index 30d0516681..a21c3e7041 100644 --- a/apps/sim/app/api/tools/cloudformation/detect-stack-drift/route.ts +++ b/apps/sim/app/api/tools/cloudformation/detect-stack-drift/route.ts @@ -48,6 +48,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to detect CloudFormation stack drift' logger.error('DetectStackDrift failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudformation/get-template/route.ts b/apps/sim/app/api/tools/cloudformation/get-template/route.ts index 9abdad4e17..a5e6edeeaa 100644 --- a/apps/sim/app/api/tools/cloudformation/get-template/route.ts +++ b/apps/sim/app/api/tools/cloudformation/get-template/route.ts @@ -45,6 +45,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to get CloudFormation template' logger.error('GetTemplate failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudformation/list-stack-resources/route.ts b/apps/sim/app/api/tools/cloudformation/list-stack-resources/route.ts index ca22c8e856..dfc6517136 100644 --- a/apps/sim/app/api/tools/cloudformation/list-stack-resources/route.ts +++ b/apps/sim/app/api/tools/cloudformation/list-stack-resources/route.ts @@ -67,6 +67,12 @@ export async function POST(request: NextRequest) { output: { resources }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to list CloudFormation stack resources' logger.error('ListStackResources failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudformation/validate-template/route.ts b/apps/sim/app/api/tools/cloudformation/validate-template/route.ts index e2a8b4428e..1264d813fd 100644 --- a/apps/sim/app/api/tools/cloudformation/validate-template/route.ts +++ b/apps/sim/app/api/tools/cloudformation/validate-template/route.ts @@ -53,6 +53,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to validate CloudFormation template' logger.error('ValidateTemplate failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudwatch/describe-alarms/route.ts b/apps/sim/app/api/tools/cloudwatch/describe-alarms/route.ts index 0ab6c4aad8..3fc65ab5bf 100644 --- a/apps/sim/app/api/tools/cloudwatch/describe-alarms/route.ts +++ b/apps/sim/app/api/tools/cloudwatch/describe-alarms/route.ts @@ -88,6 +88,12 @@ export async function POST(request: NextRequest) { output: { alarms: [...metricAlarms, ...compositeAlarms] }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to describe CloudWatch alarms' logger.error('DescribeAlarms failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudwatch/describe-log-groups/route.ts b/apps/sim/app/api/tools/cloudwatch/describe-log-groups/route.ts index a10f46c4ef..fcb29be528 100644 --- a/apps/sim/app/api/tools/cloudwatch/describe-log-groups/route.ts +++ b/apps/sim/app/api/tools/cloudwatch/describe-log-groups/route.ts @@ -54,6 +54,12 @@ export async function POST(request: NextRequest) { output: { logGroups }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to describe CloudWatch log groups' logger.error('DescribeLogGroups failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudwatch/describe-log-streams/route.ts b/apps/sim/app/api/tools/cloudwatch/describe-log-streams/route.ts index d74ad6de26..223e51617b 100644 --- a/apps/sim/app/api/tools/cloudwatch/describe-log-streams/route.ts +++ b/apps/sim/app/api/tools/cloudwatch/describe-log-streams/route.ts @@ -44,6 +44,12 @@ export async function POST(request: NextRequest) { output: { logStreams: result.logStreams }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to describe CloudWatch log streams' logger.error('DescribeLogStreams failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudwatch/get-log-events/route.ts b/apps/sim/app/api/tools/cloudwatch/get-log-events/route.ts index c42d49e97a..e1a8abcf66 100644 --- a/apps/sim/app/api/tools/cloudwatch/get-log-events/route.ts +++ b/apps/sim/app/api/tools/cloudwatch/get-log-events/route.ts @@ -52,6 +52,12 @@ export async function POST(request: NextRequest) { output: { events: result.events }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to get CloudWatch log events' logger.error('GetLogEvents failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudwatch/get-metric-statistics/route.ts b/apps/sim/app/api/tools/cloudwatch/get-metric-statistics/route.ts index 321092b328..677bafca3c 100644 --- a/apps/sim/app/api/tools/cloudwatch/get-metric-statistics/route.ts +++ b/apps/sim/app/api/tools/cloudwatch/get-metric-statistics/route.ts @@ -89,6 +89,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to get CloudWatch metric statistics' logger.error('GetMetricStatistics failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudwatch/list-metrics/route.ts b/apps/sim/app/api/tools/cloudwatch/list-metrics/route.ts index 09485cb859..36d2c31e2f 100644 --- a/apps/sim/app/api/tools/cloudwatch/list-metrics/route.ts +++ b/apps/sim/app/api/tools/cloudwatch/list-metrics/route.ts @@ -62,6 +62,12 @@ export async function POST(request: NextRequest) { output: { metrics }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'Failed to list CloudWatch metrics' logger.error('ListMetrics failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/cloudwatch/query-logs/route.ts b/apps/sim/app/api/tools/cloudwatch/query-logs/route.ts index a471edc20e..75b4dab239 100644 --- a/apps/sim/app/api/tools/cloudwatch/query-logs/route.ts +++ b/apps/sim/app/api/tools/cloudwatch/query-logs/route.ts @@ -63,6 +63,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'CloudWatch Log Insights query failed' logger.error('QueryLogs failed', { error: errorMessage }) diff --git a/apps/sim/app/api/tools/dynamodb/delete/route.ts b/apps/sim/app/api/tools/dynamodb/delete/route.ts index 0002787f37..5b6ab1d5b2 100644 --- a/apps/sim/app/api/tools/dynamodb/delete/route.ts +++ b/apps/sim/app/api/tools/dynamodb/delete/route.ts @@ -41,6 +41,12 @@ export async function POST(request: NextRequest) { message: 'Item deleted successfully', }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'DynamoDB delete failed' return NextResponse.json({ error: errorMessage }, { status: 500 }) } diff --git a/apps/sim/app/api/tools/dynamodb/get/route.ts b/apps/sim/app/api/tools/dynamodb/get/route.ts index 851f1cb074..1eca9d3f72 100644 --- a/apps/sim/app/api/tools/dynamodb/get/route.ts +++ b/apps/sim/app/api/tools/dynamodb/get/route.ts @@ -48,6 +48,12 @@ export async function POST(request: NextRequest) { item: result.item, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'DynamoDB get failed' return NextResponse.json({ error: errorMessage }, { status: 500 }) } diff --git a/apps/sim/app/api/tools/dynamodb/put/route.ts b/apps/sim/app/api/tools/dynamodb/put/route.ts index cb001c5873..2572cdcd5e 100644 --- a/apps/sim/app/api/tools/dynamodb/put/route.ts +++ b/apps/sim/app/api/tools/dynamodb/put/route.ts @@ -36,6 +36,12 @@ export async function POST(request: NextRequest) { item: validatedData.item, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'DynamoDB put failed' return NextResponse.json({ error: errorMessage }, { status: 500 }) } diff --git a/apps/sim/app/api/tools/dynamodb/query/route.ts b/apps/sim/app/api/tools/dynamodb/query/route.ts index 06945c1007..3b1fadeee1 100644 --- a/apps/sim/app/api/tools/dynamodb/query/route.ts +++ b/apps/sim/app/api/tools/dynamodb/query/route.ts @@ -51,6 +51,12 @@ export async function POST(request: NextRequest) { count: result.count, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'DynamoDB query failed' return NextResponse.json({ error: errorMessage }, { status: 500 }) } diff --git a/apps/sim/app/api/tools/dynamodb/scan/route.ts b/apps/sim/app/api/tools/dynamodb/scan/route.ts index c083faad58..64c47895b0 100644 --- a/apps/sim/app/api/tools/dynamodb/scan/route.ts +++ b/apps/sim/app/api/tools/dynamodb/scan/route.ts @@ -45,6 +45,12 @@ export async function POST(request: NextRequest) { count: result.count, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'DynamoDB scan failed' return NextResponse.json({ error: errorMessage }, { status: 500 }) } diff --git a/apps/sim/app/api/tools/dynamodb/update/route.ts b/apps/sim/app/api/tools/dynamodb/update/route.ts index 07abcc2564..3a5892fe61 100644 --- a/apps/sim/app/api/tools/dynamodb/update/route.ts +++ b/apps/sim/app/api/tools/dynamodb/update/route.ts @@ -50,6 +50,12 @@ export async function POST(request: NextRequest) { item: result.attributes, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } const errorMessage = error instanceof Error ? error.message : 'DynamoDB update failed' return NextResponse.json({ error: errorMessage }, { status: 500 }) } diff --git a/apps/sim/app/api/tools/google_drive/download/route.ts b/apps/sim/app/api/tools/google_drive/download/route.ts index 2a9730dcad..e4131423f9 100644 --- a/apps/sim/app/api/tools/google_drive/download/route.ts +++ b/apps/sim/app/api/tools/google_drive/download/route.ts @@ -240,6 +240,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { success: false, error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } logger.error(`[${requestId}] Error downloading Google Drive file:`, error) return NextResponse.json( { diff --git a/apps/sim/app/api/tools/onedrive/download/route.ts b/apps/sim/app/api/tools/onedrive/download/route.ts index a50338af55..2cc268ffd5 100644 --- a/apps/sim/app/api/tools/onedrive/download/route.ts +++ b/apps/sim/app/api/tools/onedrive/download/route.ts @@ -165,6 +165,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { success: false, error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } logger.error(`[${requestId}] Error downloading OneDrive file:`, error) return NextResponse.json( { diff --git a/apps/sim/app/api/tools/outlook/draft/route.ts b/apps/sim/app/api/tools/outlook/draft/route.ts index eeee0f14e1..801b3b9086 100644 --- a/apps/sim/app/api/tools/outlook/draft/route.ts +++ b/apps/sim/app/api/tools/outlook/draft/route.ts @@ -176,6 +176,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { success: false, error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } logger.error(`[${requestId}] Error creating Outlook draft:`, error) return NextResponse.json( { diff --git a/apps/sim/app/api/tools/outlook/send/route.ts b/apps/sim/app/api/tools/outlook/send/route.ts index f90f62518a..f2d39ef11e 100644 --- a/apps/sim/app/api/tools/outlook/send/route.ts +++ b/apps/sim/app/api/tools/outlook/send/route.ts @@ -189,6 +189,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { success: false, error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } logger.error(`[${requestId}] Error sending Outlook email:`, error) return NextResponse.json( { diff --git a/apps/sim/app/api/tools/slack/download/route.ts b/apps/sim/app/api/tools/slack/download/route.ts index 45c34bcd11..83a44386d4 100644 --- a/apps/sim/app/api/tools/slack/download/route.ts +++ b/apps/sim/app/api/tools/slack/download/route.ts @@ -158,6 +158,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { success: false, error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } logger.error(`[${requestId}] Error downloading Slack file:`, error) return NextResponse.json( { diff --git a/apps/sim/app/api/tools/slack/send-ephemeral/route.ts b/apps/sim/app/api/tools/slack/send-ephemeral/route.ts index 6d443e5039..1387290c6a 100644 --- a/apps/sim/app/api/tools/slack/send-ephemeral/route.ts +++ b/apps/sim/app/api/tools/slack/send-ephemeral/route.ts @@ -84,6 +84,12 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { success: false, error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } logger.error(`[${requestId}] Error sending ephemeral message:`, error) return NextResponse.json( { diff --git a/apps/sim/app/api/tools/slack/send-message/route.ts b/apps/sim/app/api/tools/slack/send-message/route.ts index a6b8a3db71..5520a280f6 100644 --- a/apps/sim/app/api/tools/slack/send-message/route.ts +++ b/apps/sim/app/api/tools/slack/send-message/route.ts @@ -77,6 +77,12 @@ export async function POST(request: NextRequest) { return NextResponse.json({ success: true, output: result.output }) } catch (error) { + if (error instanceof z.ZodError) { + return NextResponse.json( + { success: false, error: error.errors[0]?.message ?? 'Invalid request' }, + { status: 400 } + ) + } logger.error(`[${requestId}] Error sending Slack message:`, error) return NextResponse.json( { diff --git a/apps/sim/components/ui/copy-code-button.tsx b/apps/sim/components/ui/copy-code-button.tsx index 5113c79601..87f17764cf 100644 --- a/apps/sim/components/ui/copy-code-button.tsx +++ b/apps/sim/components/ui/copy-code-button.tsx @@ -14,10 +14,14 @@ export function CopyCodeButton({ code, className }: CopyCodeButtonProps) { const timerRef = useRef | null>(null) const handleCopy = useCallback(async () => { - await navigator.clipboard.writeText(code) - setCopied(true) - if (timerRef.current) clearTimeout(timerRef.current) - timerRef.current = setTimeout(() => setCopied(false), 2000) + try { + await navigator.clipboard.writeText(code) + setCopied(true) + if (timerRef.current) clearTimeout(timerRef.current) + timerRef.current = setTimeout(() => setCopied(false), 2000) + } catch { + // Clipboard write can fail when document lacks focus or permission is denied + } }, [code]) useEffect(