docs: private ClientResponseImpl coreCall(Object... paramListIn) {
          VoltTable[] results = null;
  
          // use local var to avoid warnings about reassigning method argument
          Object[] paramList = paramListIn;
  
          try {
              if ((m_paramTypes.length > 0) && (m_paramTypes[0] == ParameterSet.class)) {
                  assert(m_paramTypes.length == 1);
                  paramList = new Object[] { ParameterSet.fromArrayNoCopy(paramListIn) };
              }
  
              if (paramList.length != m_paramTypes.length) {
                  String msg = "PROCEDURE " + m_procedureName + " EXPECTS " + String.valueOf(m_paramTypes.length) +
                      " PARAMS, BUT RECEIVED " + String.valueOf(paramList.length);
                  m_statusCode = ClientResponse.GRACEFUL_FAILURE;
                  return ProcedureRunner.getErrorResponse(m_statusCode, m_appStatusCode, m_appStatusString, msg, null);
              }
  
              for (int i = 0; i < m_paramTypes.length; i++) {
                  try {
                      paramList[i] = ParameterConverter.tryToMakeCompatible(m_paramTypes[i], paramList[i]);
                      // check the result type in an assert
                      assert(ParameterConverter.verifyParameterConversion(paramList[i], m_paramTypes[i]));
                  } catch (Exception e) {
                      String msg = "PROCEDURE " + m_procedureName + " TYPE ERROR FOR PARAMETER " + i +
                              ": " + e.toString();
                      m_statusCode = ClientResponse.GRACEFUL_FAILURE;
                      return ProcedureRunner.getErrorResponse(m_statusCode, m_appStatusCode, m_appStatusString, msg, null);
                  }
              }
  
              try {
                  m_procedure.m_runner = this;
                  Object rawResult = m_procMethod.invoke(m_procedure, paramList);
  
                  if (rawResult instanceof CompletableFuture<?>) {
                      final CompletableFuture<?> fut = (CompletableFuture<?>) rawResult;
  
                      fut.thenRun(() -> {
                          //
                          // Happy path. No exceptions thrown. Procedure work is complete.
                          //
                          Object innerRawResult = null;
                          ClientResponseImpl response = null;
                          try {
                              innerRawResult = fut.get();
                          } catch (InterruptedException | ExecutionException e) {
                              assert(false);
                              // this is a bad place to be, but it's hard to know if it's crash bad...
                              innerRawResult = new ClientResponseImpl(ClientResponseImpl.UNEXPECTED_FAILURE,
                                      new VoltTable[0],
                                      "Future returned from NTProc " + m_procedureName + " failed to complete.",
                                      m_clientHandle);
                          }
  
                          if (innerRawResult instanceof ClientResponseImpl) {
                              response = (ClientResponseImpl) innerRawResult;
                          }
                          else {
                              try {
                                  VoltTable[] r = ParameterConverter.getResultsFromRawResults(m_procedureName, innerRawResult);
                                  response = responseFromTableArray(r);
                              } catch (Exception e) {
                                  // this is a bad place to be, but it's hard to know if it's crash bad...
                                  response = new ClientResponseImpl(ClientResponseImpl.GRACEFUL_FAILURE,
                                          new VoltTable[0],
                                          "Type " + innerRawResult.getClass().getName() +
                                              " returned from NTProc \"" + m_procedureName +
                                              "\" was not an acceptible VoltDB return type.",
                                          m_clientHandle);
                              }
                          }
  
                          completeCall(response);
                      })
                      .exceptionally(e -> {
                          //
                          // Exception path. Some bit of async work threw something.
                          //
                          SerializableException se = null;
                          if (e instanceof SerializableException) {
                              se = (SerializableException) e;
                          }
  
                          String msg = "PROCEDURE " + m_procedureName + " THREW EXCEPTION: ";
                          if (se != null) {
                              msg += se.getMessage();
                          } else {
                              msg += e.toString();
                          }
                          m_statusCode = ClientResponse.GRACEFUL_FAILURE;
                          completeCall(ProcedureRunner.getErrorResponse(m_statusCode, m_appStatusCode, m_appStatusString, msg, se));
                          return null;
                      });
  
                      return null;
                  }
                  results = ParameterConverter.getResultsFromRawResults(m_procedureName, rawResult);
              }
              catch (IllegalAccessException e) {
                  // If reflection fails, invoke the same error handling that other exceptions do
                  throw new InvocationTargetException(e);
              }
          }
          catch (InvocationTargetException itex) {
              //itex.printStackTrace();
              Throwable ex = itex.getCause();
              if (CoreUtils.isStoredProcThrowableFatalToServer(ex)) {
                  // If the stored procedure attempted to do something other than linklibrary or instantiate
                  // a missing object that results in an error, throw the error and let the server deal with
                  // the condition as best as it can (usually a crashLocalVoltDB).
                  throw (Error)ex;
              }
              return ProcedureRunner.getErrorResponse(m_procedureName,
                                                      true,
                                                      0,
                                                      m_appStatusCode,
                                                      m_appStatusString,
                                                      null,
                                                      ex);
          }
  
          return responseFromTableArray(results);
      }