private void startChildWorkflow(
      final StartChildWorkflowExecutionParameters parameters,
      final Settable<StartChildWorkflowReply> reply,
      final Settable<String> result) {
    String workflowId = parameters.getWorkflowId();
    WorkflowType workflowType = parameters.getWorkflowType();
    WorkflowExecution childExecution = new WorkflowExecution();
    final String runId = UUID.randomUUID().toString();
    // TODO: Validate parameters against registration options to find missing timeouts or other
    // options
    try {
      DecisionContext parentDecisionContext = decisionContextProvider.getDecisionContext();
      if (workflowId == null) {
        workflowId =
            decisionContextProvider.getDecisionContext().getWorkflowClient().generateUniqueId();
      }
      childExecution.setWorkflowId(workflowId);
      childExecution.setRunId(runId);

      final GenericActivityClient activityClient = parentDecisionContext.getActivityClient();
      final WorkflowClock workflowClock = parentDecisionContext.getWorkflowClock();
      WorkflowDefinitionFactory factory;
      if (factoryFactory == null) {
        throw new IllegalStateException("required property factoryFactory is null");
      }
      factory = factoryFactory.getWorkflowDefinitionFactory(workflowType);
      if (factory == null) {
        String cause =
            StartChildWorkflowExecutionFailedCause.WORKFLOW_TYPE_DOES_NOT_EXIST.toString();
        throw new StartChildWorkflowFailedException(0, childExecution, workflowType, cause);
      }
      TestWorkflowContext workflowContext = new TestWorkflowContext();
      workflowContext.setWorkflowExecution(childExecution);
      workflowContext.setWorkflowType(parameters.getWorkflowType());
      workflowContext.setParentWorkflowExecution(
          parentDecisionContext.getWorkflowContext().getWorkflowExecution());
      workflowContext.setTagList(parameters.getTagList());
      workflowContext.setTaskList(parameters.getTaskList());
      DecisionContext context =
          new TestDecisionContext(
              activityClient, TestGenericWorkflowClient.this, workflowClock, workflowContext);
      // this, parameters, childExecution, workflowClock, activityClient);
      final WorkflowDefinition childWorkflowDefinition = factory.getWorkflowDefinition(context);
      final ChildWorkflowTryCatchFinally tryCatch =
          new ChildWorkflowTryCatchFinally(
              parameters, childExecution, childWorkflowDefinition, context, result);
      workflowContext.setRootTryCatch(tryCatch);
      ChildWorkflowTryCatchFinally currentRun = workflowExecutions.get(workflowId);
      if (currentRun != null) {
        String cause = StartChildWorkflowExecutionFailedCause.WORKFLOW_ALREADY_RUNNING.toString();
        throw new StartChildWorkflowFailedException(0, childExecution, workflowType, cause);
      }
      workflowExecutions.put(workflowId, tryCatch);
      continueAsNewWorkflowExecution(tryCatch, result);
    } catch (StartChildWorkflowFailedException e) {
      throw e;
    } catch (Throwable e) {
      // This cause is chosen to represent internal error for sub-workflow creation
      String cause = StartChildWorkflowExecutionFailedCause.OPEN_CHILDREN_LIMIT_EXCEEDED.toString();
      StartChildWorkflowFailedException failure =
          new StartChildWorkflowFailedException(0, childExecution, workflowType, cause);
      failure.initCause(e);
      throw failure;
    } finally {
      reply.set(new StartChildWorkflowReplyImpl(result, runId));
    }
  }