@@ -1156,12 +1156,13 @@ async function readToolResponseBody(
11561156 * is logged: an internal operation's or a Function's body carries the author's data, stdout, and
11571157 * source lines.
11581158 */
1159- const externalHttpFailures = new WeakSet < Error > ( )
1159+ const externalHttpFailures = new WeakSet < object > ( )
11601160
11611161function createExternalHttpFailure ( errorInfo ?: ErrorInfo , extractorId ?: string ) : Error {
11621162 const failure = createTransformedErrorFromErrorInfo ( errorInfo , extractorId )
11631163 externalHttpFailures . add ( failure )
1164- return failure
1164+ /** An error payload on a 2xx carries no status but is still the provider refusing. */
1165+ return errorInfo ?. status === undefined ? markFailureKind ( failure , 'third_party_client' ) : failure
11651166}
11661167
11671168/**
@@ -2338,9 +2339,7 @@ async function executeToolImplementation(
23382339 : {
23392340 error : normalizedError . message ,
23402341 stack : error instanceof Error ? error . stack : undefined ,
2341- ...( error instanceof Error && externalHttpFailures . has ( error )
2342- ? { errorData : error . data }
2343- : { } ) ,
2342+ ...( externalHttpFailures . has ( error ) ? { errorData : error . data } : { } ) ,
23442343 } ) ,
23452344 } ,
23462345 resolvedSecretTraceRegistry ,
@@ -2843,6 +2842,11 @@ async function executeDeclaredInternalOperation({
28432842 }
28442843}
28452844
2845+ /** A tool or proxy URL the author configured that Sim refuses to call; the author's to fix. */
2846+ function invalidToolTarget ( message : string ) : Error {
2847+ return markFailureKind ( new Error ( message ) , 'user' )
2848+ }
2849+
28462850/** Executes one external tool request with DNS validation and IP pinning. */
28472851async function executeToolRequest (
28482852 toolId : string ,
@@ -2860,7 +2864,7 @@ async function executeToolRequest(
28602864 const targetsThisSimInstance = isSelfOriginUrl ( fullUrl )
28612865
28622866 if ( targetsThisSimInstance && tool . request . allowSameOrigin !== true ) {
2863- throw new Error ( SAME_ORIGIN_EXTERNAL_TOOL_ERROR_MESSAGE )
2867+ throw invalidToolTarget ( SAME_ORIGIN_EXTERNAL_TOOL_ERROR_MESSAGE )
28642868 }
28652869
28662870 if ( targetsThisSimInstance ) {
@@ -2892,14 +2896,14 @@ async function executeToolRequest(
28922896 try {
28932897 const urlValidation = await validateUrlWithDNS ( fullUrl , 'toolUrl' , 'requestTarget' )
28942898 if ( ! urlValidation . isValid ) {
2895- throw new Error ( `Invalid tool URL: ${ urlValidation . error } ` )
2899+ throw invalidToolTarget ( `Invalid tool URL: ${ urlValidation . error } ` )
28962900 }
28972901
28982902 let proxyOption : string | undefined
28992903 if ( requestParams . proxyUrl ) {
29002904 const proxyValidation = await validateAndPinProxyUrl ( requestParams . proxyUrl )
29012905 if ( ! proxyValidation . isValid ) {
2902- throw new Error ( `Invalid proxy URL: ${ proxyValidation . error } ` )
2906+ throw invalidToolTarget ( `Invalid proxy URL: ${ proxyValidation . error } ` )
29032907 }
29042908 proxyOption = proxyValidation . pinnedProxyUrl
29052909 }
@@ -2920,7 +2924,7 @@ async function executeToolRequest(
29202924 ? undefined
29212925 : ( redirectUrl ) => {
29222926 if ( isSelfOriginUrl ( redirectUrl ) ) {
2923- throw new Error ( SAME_ORIGIN_EXTERNAL_TOOL_ERROR_MESSAGE )
2927+ throw invalidToolTarget ( SAME_ORIGIN_EXTERNAL_TOOL_ERROR_MESSAGE )
29242928 }
29252929 } ,
29262930 } )
@@ -3314,6 +3318,13 @@ async function executeMcpTool(
33143318 const endTimeISO = endTime . toISOString ( )
33153319 const duration = endTime . getTime ( ) - new Date ( actualStartTime ) . getTime ( )
33163320
3321+ /** These lines replace the block executor's, so they carry the run identity themselves. */
3322+ const blockId = toRecord ( params . _context ) . blockId
3323+ const runIdentity = {
3324+ workflowId : context ?. workflowId ,
3325+ executionId : context ?. executionId ,
3326+ blockId : typeof blockId === 'string' ? blockId : undefined ,
3327+ }
33173328 const errorMsg = toError ( error ) . message
33183329 if ( isBodySizeLimitError ( errorMsg ) ) {
33193330 const failure = bodySizeLimitError ( )
@@ -3322,14 +3333,14 @@ async function executeMcpTool(
33223333 `[${ actualRequestId } ] Request body size limit exceeded for mcp:${ toolId } :` ,
33233334 failure ,
33243335 {
3325- metadata : ( ) =>
3326- projectToolLogMetadata (
3336+ metadata : ( ) => ( {
3337+ ...runIdentity ,
3338+ ...projectToolLogMetadata (
33273339 { originalError : errorMsg } ,
33283340 context ?. resolvedSecretTraceRegistry ,
3329- {
3330- hasOriginalError : errorMsg . length > 0 ,
3331- }
3341+ { hasOriginalError : errorMsg . length > 0 }
33323342 ) ,
3343+ } ) ,
33333344 }
33343345 )
33353346 return {
@@ -3346,8 +3357,9 @@ async function executeMcpTool(
33463357
33473358 const normalizedError = toError ( error )
33483359 logFailureOnce ( logger , `[${ actualRequestId } ] Error executing MCP tool ${ toolId } :` , error , {
3349- metadata : ( ) =>
3350- projectToolLogMetadata (
3360+ metadata : ( ) => ( {
3361+ ...runIdentity ,
3362+ ...projectToolLogMetadata (
33513363 {
33523364 error : normalizedError . message ,
33533365 stack : error instanceof Error ? error . stack : undefined ,
@@ -3358,6 +3370,7 @@ async function executeMcpTool(
33583370 hasStack : Boolean ( error instanceof Error && error . stack ) ,
33593371 }
33603372 ) ,
3373+ } ) ,
33613374 } )
33623375
33633376 const errorMessage = getErrorMessage ( error , `Failed to execute MCP tool ${ toolId } ` )
0 commit comments