@@ -16,6 +16,84 @@ import {
1616
1717const logger = createLogger ( 'Tools' )
1818
19+ /**
20+ * Maximum request body size in bytes before we warn/error about size limits.
21+ * Next.js 16 has a default middleware/proxy body limit of 10MB.
22+ */
23+ const MAX_REQUEST_BODY_SIZE_BYTES = 10 * 1024 * 1024 // 10MB
24+
25+ /**
26+ * User-friendly error message for body size limit exceeded
27+ */
28+ const BODY_SIZE_LIMIT_ERROR_MESSAGE =
29+ 'Request body size limit exceeded (10MB). The workflow data is too large to process. Try reducing the size of variables, inputs, or data being passed between blocks.'
30+
31+ /**
32+ * Validates request body size and throws a user-friendly error if exceeded
33+ * @param body - The request body string to check
34+ * @param requestId - Request ID for logging
35+ * @param context - Context string for logging (e.g., toolId)
36+ * @throws Error if body size exceeds the limit
37+ */
38+ function validateRequestBodySize (
39+ body : string | undefined ,
40+ requestId : string ,
41+ context : string
42+ ) : void {
43+ if ( ! body ) return
44+
45+ const bodySize = Buffer . byteLength ( body , 'utf8' )
46+ if ( bodySize > MAX_REQUEST_BODY_SIZE_BYTES ) {
47+ const bodySizeMB = ( bodySize / ( 1024 * 1024 ) ) . toFixed ( 2 )
48+ const maxSizeMB = ( MAX_REQUEST_BODY_SIZE_BYTES / ( 1024 * 1024 ) ) . toFixed ( 0 )
49+ logger . error ( `[${ requestId } ] Request body size exceeds limit for ${ context } :` , {
50+ bodySize,
51+ bodySizeMB : `${ bodySizeMB } MB` ,
52+ maxSize : MAX_REQUEST_BODY_SIZE_BYTES ,
53+ maxSizeMB : `${ maxSizeMB } MB` ,
54+ } )
55+ throw new Error ( BODY_SIZE_LIMIT_ERROR_MESSAGE )
56+ }
57+ }
58+
59+ /**
60+ * Checks if an error message indicates a body size limit issue
61+ * @param errorMessage - The error message to check
62+ * @returns true if the error is related to body size limits
63+ */
64+ function isBodySizeLimitError ( errorMessage : string ) : boolean {
65+ const lowerMessage = errorMessage . toLowerCase ( )
66+ return (
67+ lowerMessage . includes ( 'body size' ) ||
68+ lowerMessage . includes ( 'payload too large' ) ||
69+ lowerMessage . includes ( 'entity too large' ) ||
70+ lowerMessage . includes ( 'request entity too large' ) ||
71+ lowerMessage . includes ( 'body_not_allowed' ) ||
72+ lowerMessage . includes ( 'request body larger than' )
73+ )
74+ }
75+
76+ /**
77+ * Handles body size limit errors by logging and throwing a user-friendly error
78+ * @param error - The original error
79+ * @param requestId - Request ID for logging
80+ * @param context - Context string for logging (e.g., toolId)
81+ * @throws Error with user-friendly message if it's a size limit error
82+ * @returns false if not a size limit error (caller should continue handling)
83+ */
84+ function handleBodySizeLimitError ( error : unknown , requestId : string , context : string ) : boolean {
85+ const errorMessage = error instanceof Error ? error . message : String ( error )
86+
87+ if ( isBodySizeLimitError ( errorMessage ) ) {
88+ logger . error ( `[${ requestId } ] Request body size limit exceeded for ${ context } :` , {
89+ originalError : errorMessage ,
90+ } )
91+ throw new Error ( BODY_SIZE_LIMIT_ERROR_MESSAGE )
92+ }
93+
94+ return false
95+ }
96+
1997/**
2098 * System parameters that should be filtered out when extracting tool arguments
2199 * These are internal parameters used by the execution framework, not tool inputs
@@ -537,6 +615,9 @@ async function handleInternalRequest(
537615 const headers = new Headers ( requestParams . headers )
538616 await addInternalAuthIfNeeded ( headers , isInternalRoute , requestId , toolId )
539617
618+ // Check request body size before sending to detect potential size limit issues
619+ validateRequestBodySize ( requestParams . body , requestId , toolId )
620+
540621 // Prepare request options
541622 const requestOptions = {
542623 method : requestParams . method ,
@@ -548,6 +629,15 @@ async function handleInternalRequest(
548629
549630 // For non-OK responses, attempt JSON first; if parsing fails, fall back to text
550631 if ( ! response . ok ) {
632+ // Check for 413 (Entity Too Large) - body size limit exceeded
633+ if ( response . status === 413 ) {
634+ logger . error ( `[${ requestId } ] Request body too large for ${ toolId } (HTTP 413):` , {
635+ status : response . status ,
636+ statusText : response . statusText ,
637+ } )
638+ throw new Error ( BODY_SIZE_LIMIT_ERROR_MESSAGE )
639+ }
640+
551641 let errorData : any
552642 try {
553643 errorData = await response . json ( )
@@ -645,6 +735,9 @@ async function handleInternalRequest(
645735 error : undefined ,
646736 }
647737 } catch ( error : any ) {
738+ // Check if this is a body size limit error and throw user-friendly message
739+ handleBodySizeLimitError ( error , requestId , toolId )
740+
648741 logger . error ( `[${ requestId } ] Internal request error for ${ toolId } :` , {
649742 error : error instanceof Error ? error . message : String ( error ) ,
650743 } )
@@ -737,13 +830,24 @@ async function handleProxyRequest(
737830 const headers : Record < string , string > = { 'Content-Type' : 'application/json' }
738831 await addInternalAuthIfNeeded ( headers , true , requestId , `proxy:${ toolId } ` )
739832
833+ const body = JSON . stringify ( { toolId, params, executionContext } )
834+
835+ // Check request body size before sending
836+ validateRequestBodySize ( body , requestId , `proxy:${ toolId } ` )
837+
740838 const response = await fetch ( proxyUrl , {
741839 method : 'POST' ,
742840 headers,
743- body : JSON . stringify ( { toolId , params , executionContext } ) ,
841+ body,
744842 } )
745843
746844 if ( ! response . ok ) {
845+ // Check for 413 (Entity Too Large) - body size limit exceeded
846+ if ( response . status === 413 ) {
847+ logger . error ( `[${ requestId } ] Request body too large for proxy:${ toolId } (HTTP 413)` )
848+ throw new Error ( BODY_SIZE_LIMIT_ERROR_MESSAGE )
849+ }
850+
747851 const errorText = await response . text ( )
748852 logger . error ( `[${ requestId } ] Proxy request failed for ${ toolId } :` , {
749853 status : response . status ,
@@ -783,6 +887,9 @@ async function handleProxyRequest(
783887 const result = await response . json ( )
784888 return result
785889 } catch ( error : any ) {
890+ // Check if this is a body size limit error and throw user-friendly message
891+ handleBodySizeLimitError ( error , requestId , `proxy:${ toolId } ` )
892+
786893 logger . error ( `[${ requestId } ] Proxy request error for ${ toolId } :` , {
787894 error : error instanceof Error ? error . message : String ( error ) ,
788895 } )
@@ -880,6 +987,11 @@ async function executeMcpTool(
880987 workspaceId, // Pass workspace context for scoping
881988 }
882989
990+ const body = JSON . stringify ( requestBody )
991+
992+ // Check request body size before sending
993+ validateRequestBodySize ( body , actualRequestId , `mcp:${ toolId } ` )
994+
883995 logger . info ( `[${ actualRequestId } ] Making MCP tool request to ${ toolName } on ${ serverId } ` , {
884996 hasWorkspaceId : ! ! workspaceId ,
885997 hasWorkflowId : ! ! workflowId ,
@@ -888,14 +1000,29 @@ async function executeMcpTool(
8881000 const response = await fetch ( `${ baseUrl } /api/mcp/tools/execute` , {
8891001 method : 'POST' ,
8901002 headers,
891- body : JSON . stringify ( requestBody ) ,
1003+ body,
8921004 } )
8931005
8941006 const endTime = new Date ( )
8951007 const endTimeISO = endTime . toISOString ( )
8961008 const duration = endTime . getTime ( ) - new Date ( actualStartTime ) . getTime ( )
8971009
8981010 if ( ! response . ok ) {
1011+ // Check for 413 (Entity Too Large) - body size limit exceeded
1012+ if ( response . status === 413 ) {
1013+ logger . error ( `[${ actualRequestId } ] Request body too large for mcp:${ toolId } (HTTP 413)` )
1014+ return {
1015+ success : false ,
1016+ output : { } ,
1017+ error : BODY_SIZE_LIMIT_ERROR_MESSAGE ,
1018+ timing : {
1019+ startTime : actualStartTime ,
1020+ endTime : endTimeISO ,
1021+ duration,
1022+ } ,
1023+ }
1024+ }
1025+
8991026 let errorMessage = `MCP tool execution failed: ${ response . status } ${ response . statusText } `
9001027
9011028 try {
@@ -950,6 +1077,24 @@ async function executeMcpTool(
9501077 const endTimeISO = endTime . toISOString ( )
9511078 const duration = endTime . getTime ( ) - new Date ( actualStartTime ) . getTime ( )
9521079
1080+ // Check if this is a body size limit error
1081+ const errorMsg = error instanceof Error ? error . message : String ( error )
1082+ if ( isBodySizeLimitError ( errorMsg ) ) {
1083+ logger . error ( `[${ actualRequestId } ] Request body size limit exceeded for mcp:${ toolId } :` , {
1084+ originalError : errorMsg ,
1085+ } )
1086+ return {
1087+ success : false ,
1088+ output : { } ,
1089+ error : BODY_SIZE_LIMIT_ERROR_MESSAGE ,
1090+ timing : {
1091+ startTime : actualStartTime ,
1092+ endTime : endTimeISO ,
1093+ duration,
1094+ } ,
1095+ }
1096+ }
1097+
9531098 logger . error ( `[${ actualRequestId } ] Error executing MCP tool ${ toolId } :` , error )
9541099
9551100 const errorMessage =
0 commit comments