@@ -1155,12 +1155,13 @@ async function readToolResponseBody(
11551155 * is logged: an internal operation's or a Function's body carries the author's data, stdout, and
11561156 * source lines.
11571157 */
1158- const externalHttpFailures = new WeakSet < Error > ( )
1158+ const externalHttpFailures = new WeakSet < object > ( )
11591159
11601160function createExternalHttpFailure ( errorInfo ?: ErrorInfo , extractorId ?: string ) : Error {
11611161 const failure = createTransformedErrorFromErrorInfo ( errorInfo , extractorId )
11621162 externalHttpFailures . add ( failure )
1163- return failure
1163+ /** An error payload on a 2xx carries no status but is still the provider refusing. */
1164+ return errorInfo ?. status === undefined ? markFailureKind ( failure , 'third_party_client' ) : failure
11641165}
11651166
11661167/**
@@ -2334,9 +2335,7 @@ async function executeToolImplementation(
23342335 : {
23352336 error : normalizedError . message ,
23362337 stack : error instanceof Error ? error . stack : undefined ,
2337- ...( error instanceof Error && externalHttpFailures . has ( error )
2338- ? { errorData : error . data }
2339- : { } ) ,
2338+ ...( externalHttpFailures . has ( error ) ? { errorData : error . data } : { } ) ,
23402339 } ) ,
23412340 } ,
23422341 resolvedSecretTraceRegistry ,
@@ -2839,6 +2838,11 @@ async function executeDeclaredInternalOperation({
28392838 }
28402839}
28412840
2841+ /** A tool or proxy URL the author configured that Sim refuses to call; the author's to fix. */
2842+ function invalidToolTarget ( message : string ) : Error {
2843+ return markFailureKind ( new Error ( message ) , 'user' )
2844+ }
2845+
28422846/** Executes one external tool request with DNS validation and IP pinning. */
28432847async function executeToolRequest (
28442848 toolId : string ,
@@ -2856,7 +2860,7 @@ async function executeToolRequest(
28562860 const targetsThisSimInstance = isSelfOriginUrl ( fullUrl )
28572861
28582862 if ( targetsThisSimInstance && tool . request . allowSameOrigin !== true ) {
2859- throw new Error ( SAME_ORIGIN_EXTERNAL_TOOL_ERROR_MESSAGE )
2863+ throw invalidToolTarget ( SAME_ORIGIN_EXTERNAL_TOOL_ERROR_MESSAGE )
28602864 }
28612865
28622866 if ( targetsThisSimInstance ) {
@@ -2888,14 +2892,14 @@ async function executeToolRequest(
28882892 try {
28892893 const urlValidation = await validateUrlWithDNS ( fullUrl , 'toolUrl' , 'requestTarget' )
28902894 if ( ! urlValidation . isValid ) {
2891- throw new Error ( `Invalid tool URL: ${ urlValidation . error } ` )
2895+ throw invalidToolTarget ( `Invalid tool URL: ${ urlValidation . error } ` )
28922896 }
28932897
28942898 let proxyOption : string | undefined
28952899 if ( requestParams . proxyUrl ) {
28962900 const proxyValidation = await validateAndPinProxyUrl ( requestParams . proxyUrl )
28972901 if ( ! proxyValidation . isValid ) {
2898- throw new Error ( `Invalid proxy URL: ${ proxyValidation . error } ` )
2902+ throw invalidToolTarget ( `Invalid proxy URL: ${ proxyValidation . error } ` )
28992903 }
29002904 proxyOption = proxyValidation . pinnedProxyUrl
29012905 }
@@ -2916,7 +2920,7 @@ async function executeToolRequest(
29162920 ? undefined
29172921 : ( redirectUrl ) => {
29182922 if ( isSelfOriginUrl ( redirectUrl ) ) {
2919- throw new Error ( SAME_ORIGIN_EXTERNAL_TOOL_ERROR_MESSAGE )
2923+ throw invalidToolTarget ( SAME_ORIGIN_EXTERNAL_TOOL_ERROR_MESSAGE )
29202924 }
29212925 } ,
29222926 } )
@@ -3310,6 +3314,13 @@ async function executeMcpTool(
33103314 const endTimeISO = endTime . toISOString ( )
33113315 const duration = endTime . getTime ( ) - new Date ( actualStartTime ) . getTime ( )
33123316
3317+ /** These lines replace the block executor's, so they carry the run identity themselves. */
3318+ const blockId = toRecord ( params . _context ) . blockId
3319+ const runIdentity = {
3320+ workflowId : context ?. workflowId ,
3321+ executionId : context ?. executionId ,
3322+ blockId : typeof blockId === 'string' ? blockId : undefined ,
3323+ }
33133324 const errorMsg = toError ( error ) . message
33143325 if ( isBodySizeLimitError ( errorMsg ) ) {
33153326 const failure = bodySizeLimitError ( )
@@ -3318,14 +3329,14 @@ async function executeMcpTool(
33183329 `[${ actualRequestId } ] Request body size limit exceeded for mcp:${ toolId } :` ,
33193330 failure ,
33203331 {
3321- metadata : ( ) =>
3322- projectToolLogMetadata (
3332+ metadata : ( ) => ( {
3333+ ...runIdentity ,
3334+ ...projectToolLogMetadata (
33233335 { originalError : errorMsg } ,
33243336 context ?. resolvedSecretTraceRegistry ,
3325- {
3326- hasOriginalError : errorMsg . length > 0 ,
3327- }
3337+ { hasOriginalError : errorMsg . length > 0 }
33283338 ) ,
3339+ } ) ,
33293340 }
33303341 )
33313342 return {
@@ -3342,8 +3353,9 @@ async function executeMcpTool(
33423353
33433354 const normalizedError = toError ( error )
33443355 logFailureOnce ( logger , `[${ actualRequestId } ] Error executing MCP tool ${ toolId } :` , error , {
3345- metadata : ( ) =>
3346- projectToolLogMetadata (
3356+ metadata : ( ) => ( {
3357+ ...runIdentity ,
3358+ ...projectToolLogMetadata (
33473359 {
33483360 error : normalizedError . message ,
33493361 stack : error instanceof Error ? error . stack : undefined ,
@@ -3354,6 +3366,7 @@ async function executeMcpTool(
33543366 hasStack : Boolean ( error instanceof Error && error . stack ) ,
33553367 }
33563368 ) ,
3369+ } ) ,
33573370 } )
33583371
33593372 const errorMessage = getErrorMessage ( error , `Failed to execute MCP tool ${ toolId } ` )
0 commit comments