Child workflow error handling

I have two workflows, parent and child. The child workflow calls certain activities that error with a specific error message. As such, sometimes the child workflow will fail due to these errors. However, the error that the parent workflow receives from the child workflow failing does not contain the relevant error message. Is there anyway that I can get this to work as intended?
For context I’m on Temporal typescript sdk version 1.4.3.

As an example code block
parent workflow:

try {
    const result = await executeChild(childWorkflow);
} catch (err) {
    await activities.reportError(err);
}

childWorkflow:

await activity.trySomething();

activities:

async function trySomething():
    throw Error('Trying to extract this specific text')

It seems like my childWorkflow (based on the Temporal UI), will get something, as an event of ActivityTaskFailed.

{
  "message": "Trying to extract this specific text",
  "source": "TypeScriptSDK",
  "stackTrace": "Trying to extract this specific text at Activity...",
  "cause": null,
  "applicationFailureInfo": {
    "type": "TypeError",
    "nonRetryable": false,
    "details": null
  }
}

What I see in the Temporal UI as the last event (which is WorkflowExecutionFailed)

{
  "message": "Activity execution failed",
  "source": "TypeScriptSDK",
  "stackTrace": "",
  "cause": null,
  "applicationFailureInfo": {
    "type": "ActivityFailure",
    "nonRetryable": false,
    "details": null
  }
}

and what’s in the results window of the child workflow is

{
  "type": "workflowExecutionFailedEventAttributes",
  "failure": {
    "message": "Activity execution failed",
    "source": "TypeScriptSDK",
    "stackTrace": "",
    "cause": null,
    "applicationFailureInfo": {
      "type": "ActivityFailure",
      "nonRetryable": false,
      "details": null
    }
  },
  "retryState": "RetryPolicyNotSet",
  "workflowTaskCompletedEventId": "10",
  "newExecutionRunId": ""
}

Lastly what’s returned to the parent workflow seems to be that last event of WorkflowExecutionFailed. So it seems that the error is returned as intended to the workflow, with some additional metdata. But what the child workflow does when it returns this error is that it actually discards the initial error, and wraps it or something. Is this intentional or am I doing something wrong here? Otherwise, how am I able to get that text/message from the error returned from the activity?

Are you wrapping this line in any way from workflow code or an interceptor?

That might explain what you’re seeing here.
What I would expect is that the child workflow fails with cause set to the activity failure but for some reason it’s not what’s happening the way you’ve set things up.

Could you share the full execution history json for parent and child please?

tctl wf show -w <wfid> -r <runid> --of myhistory.json

Hmm, I think we do have an interceptor, going to be looking at that. Thanks for pointing that out.

/*
   1  WorkflowExecutionStarted  {WorkflowType:{Name:executeHuman}, ParentWorkflowNamespace:default,                                                                  
                                ParentWorkflowNamespaceId:36ca4857-ecdf-4998-964e-e54c63a36c50, ParentWorkflowExecution:{WorkflowId:n-SODKkkJyJEQY9yRAWQhYD,         
                                RunId:88462154-8488-439b-be1c-afa1748964d0}, ParentInitiatedEventId:11, TaskQueue:{Name:workflows, Kind:Normal},                     
                                Input:[{"node":{"nodeName":"humanTaskerNode","type":"human","status":"active","dependencies":["n-unAu4SdZe1e2qj4Py1vBV"],"reso       
                                urceDependencies":["r-wcoPQxuJ9l6Ao7yrXKZ5d"],"id":"n-SODKkkJyJEQY9yRAWQhYD","createdAt":"2022-11-16T22:00:01.410Z"},"ta skInfo":{"  
                                ... ue":{"storageType":"raw","value":{"reviewLevel":-1}},"sourcePipelineResourceKey":"reviewLevelSelectorOutput","version":2         
                                ,"sourcePipelineResource":true}]}, {"type":"human","resourceDependencies":["human_node_input"],"runOutputTransformationFn":false}],  
                                WorkflowRunTimeout:0s, WorkflowTaskTimeout:10s, Initiator:Unspecified, OriginalExecutionRunId:6fcd3f63-c8f2-4f94-832e-4765a13e779b,  
                                FirstExecutionRunId:6fcd3f63-c8f2-4f94-832e-4765a13e779b, Attempt:1, FirstWorkflowTaskBackoff:0s,                                    
                                Header:{Fields:map{_tracer-data:{"traceparent":"00-098a5bb06e2afc3c164d73e420fb6a90-4da411cfff6a5930-01"}}},                         
                                ParentInitiatedEventVersion:0}                                                                                                       
   2  WorkflowTaskScheduled     {TaskQueue:{Name:workflows,                                                                                                          
                                Kind:Normal},                                                                                                                        
                                StartToCloseTimeout:10s,                                                                                                             
                                Attempt:1}                                                                                                                           
   3  WorkflowTaskStarted       {ScheduledEventId:2,                                                                                                                 
                                Identity:26671@SCMK69THJ2P7Q,                                                                                                        
                                RequestId:7e03a5ac-9d04-400b-894a-1a3d332a397d,                                                                                      
                                SuggestContinueAsNew:false, HistorySizeBytes:0}                                                                                      
   4  WorkflowTaskCompleted     {ScheduledEventId:2, StartedEventId:3, Identity:26671@SCMK69THJ2P7Q,                                                                 
                                BinaryChecksum:@temporalio/worker@1.4.3+6d805ff54a06a997c41a549a2ce984e980a1fe44db25531a7777d2c0f53ac7bd}                            
   5  ActivityTaskScheduled     {ActivityId:1, ActivityType:{Name:testActivity}, TaskQueue:{Name:main-service, Kind:Normal},                 
                                Header:{Fields:map{_tracer-data:{"traceparent":"00-098a5bb06e2afc3c164d73e420fb6a90-a2c0801a0981cb6a-01"}}},                         
                                Input:[{"node":{"nodeName":"humanTaskerNode","type":"human","status":"active","dependencies":["n-unAu4SdZe1e2qj4Py1vBV"],"reso       
                                urceDependencies":["r-wcoPQxuJ9l6Ao7yrXKZ5d"],"id":"n-SODKkkJyJEQY9yRAWQhYD","createdAt":"2022-11-16T22:00:01.410Z"},"ta skInfo":{"  
                                ... 54a978c66cf1597e1","name":"human_node_input","sourcePipelineNode":"n-unAu4SdZe1e2qj4Py1vBV","value":{"storageType":"raw"         
                                ,"value":{"reviewLevel":-1}},"sourcePipelineResourceKey":"reviewLevelSelectorOutput","version":2,"sourcePipelineResource             
                                ":true}]}], ScheduleToCloseTimeout:1m0s, ScheduleToStartTimeout:1m0s, StartToCloseTimeout:1m0s, HeartbeatTimeout:1m0s,               
                                WorkflowTaskCompletedEventId:4, RetryPolicy:{InitialInterval:1s, BackoffCoefficient:2, MaximumInterval:1h0m0s, MaximumAttempts:0,    
                                NonRetryableErrorTypes:[]}}                                                                                                          
   6  ActivityTaskStarted       {ScheduledEventId:5, Identity:26685@SCMK69THJ2P7Q, RequestId:03271db3-a2d8-4b63-9250-028e28092237,                                   
                                Attempt:6, LastFailure:{Message:Cannot read properties of undefined (reading                                                         
                                's'), Source:TypeScriptSDK, StackTrace:TypeError: Cannot read properties of                                                          
                                undefined (reading 's')     at Activity.testActivity [as fn]                                                 
                                (/Users/user/project/server/src/testActivity.ts:12:17),                       
                                FailureInfo:{ApplicationFailureInfo:{Type:TypeError, NonRetryable:false}}}}                                                          
   7  ActivityTaskFailed        {Failure:{Message:Cannot read properties of undefined (reading 's'),                                                                 
                                Source:TypeScriptSDK, StackTrace:TypeError: Cannot read properties of undefined                                                      
                                (reading 's')     at Activity.testActivity [as fn]                                                           
                                (/Users/user/project/server/src/testActivity.ts:12:17),                       
                                FailureInfo:{ApplicationFailureInfo:{Type:TypeError, NonRetryable:false}}}, ScheduledEventId:5,                                      
                                StartedEventId:6, Identity:26685@SCMK69THJ2P7Q, RetryState:Timeout}                                                                  
   8  WorkflowTaskScheduled     {TaskQueue:{Name:26671@SCMK69THJ2P7Q-workflows-908fdfb25b0a49c6b3f7540519e401b8,                                                     
                                Kind:Sticky}, StartToCloseTimeout:10s, Attempt:1}                                                                                    
   9  WorkflowTaskStarted       {ScheduledEventId:8,                                                                                                                 
                                Identity:26671@SCMK69THJ2P7Q,                                                                                                        
                                RequestId:8afd84b2-c2a5-4e7c-b5b2-9c31b7dbdb15,                                                                                      
                                SuggestContinueAsNew:false, HistorySizeBytes:0}                                                                                      
  10  WorkflowTaskCompleted     {ScheduledEventId:8, StartedEventId:9, Identity:26671@SCMK69THJ2P7Q,                                                                 
                                BinaryChecksum:@temporalio/worker@1.4.3+6d805ff54a06a997c41a549a2ce984e980a1fe44db25531a7777d2c0f53ac7bd}                            
  11  WorkflowExecutionFailed   {Failure:{Message:Activity                                                                                                           
                                execution failed, Source:TypeScriptSDK,                                                                                              
                                FailureInfo:{ApplicationFailureInfo:{Type:ActivityFailure,                                                                           
                                NonRetryable:false}}}, RetryState:RetryPolicyNotSet,                                                                                 
                                WorkflowTaskCompletedEventId:10}  
*/

Thanks for info, this is one of the child workflows that failed due to activity failure (after 6 retry attempts), correct? Could you also share the parent workflow history please?

By the way regarding your activity options:
ScheduleToCloseTimeout:1m0s
ScheduleToStartTimeout:1m0s
StartToCloseTimeout:1m0s
HeartbeatTimeout:1m0s

Don’t think you need to set ScheduleToStartTimeout unless you have business case for it.
Don’t set same value for StartToClose (max execution timeout for single activity execution) and ScheduleToClose (max execution timeout for activity execution including all retries).
Is your activity heartbeating? If it does not there is no need to set HeartbeatTimeout.

For activity timeouts see video here.

The ScheduleToCloseTimeout value was just set very low since I wanted to test a normal Error that could come up at runtime (instead of an Activity or ApplicationFailure that’s configured to not retry). We typically just leave that value as a day for a business case. We also do have heartbeats on some of our activities.

We provide that startToClose value as a default value, sometimes its overridden, but by default we don’t want to allow super long running activities as (in our case) it typically points to a production issue.

I’ve now fixed my interceptor, the problem was that before I was basing it off of this (sdk-typescript/workflow-log-interceptor.ts at main · temporalio/sdk-typescript · GitHub), but I also added an ensureApplicationFailure fn call to the error before returning it.

Something I’d also like to understand better (maybe this is just specific to the Temporal typescript SDK), is how error handling works between activities, workflows and child->parent workflows. My understanding is that any error from an activity is wrapped inside an ApplicationFailure, with the error stored inside the cause field, when it’s returned to the workflow that invoked that activity. And then for child to parent workflows, any error that the child workflow causes, will then be wrapped in an ChildWorkflowFailure. Is this always the case? Can you also shed light on why it’s wrapped in an ApplicationFailure instead of ActivityFailure