toPassableError = err => {
  harden(err);
  if (checkRecursivelyPassableError(err, passStyleOf)) {
    return err;
  }
  const { name, message } = err;
  const { cause: causeDesc, errors: errorsDesc } =
    getOwnPropertyDescriptors(err);
  let cause;
  let errors;
  if (causeDesc && isPassableErrorPropertyDesc('cause', causeDesc)) {
    cause = causeDesc.value;
  }
  if (errorsDesc && isPassableErrorPropertyDesc('errors', errorsDesc)) {
    errors = errorsDesc.value;
  }

  const errConstructor = getErrorConstructor(`${name}`) || Error;
  const newError = makeError(`${message}`, errConstructor, {
    // @ts-ignore Assuming cause is Error | undefined
    cause,
    errors,
  });
  // Still needed, because `makeError` only does a shallow freeze.
  harden(newError);
  // Even the cleaned up error copy, if sent to the console, should
  // cause hidden diagnostic information of the original error
  // to be logged.
  annotateError(newError, X`copied from error ${err}`);
  passStyleOf(newError) === 'error' ||
    Fail`Expected ${newError} to be a passable error`;
  return newError;
}
After hardening, if `err` is a passable error, return it.

Otherwise, return a new passable error that propagates the diagnostic
info of the original, and is linked to the original as a note.

TODO Adopt a more flexible notion of passable error, in which
a passable error can contain other own data properties with
throwable values.

@param {Error} err
@returns {Error}