# Buggy code
def send_(self, workers):
    """
    Sends a Variable object to a (sequence of) Grid workers.

    Args:
    workers: string (or sequence) containing IPFS address(es)
        of worker node(s).
    """

    # makes singleton if needed
    workers = hook_self.local_worker._check_workers(self, workers)
    self = hook_self.local_worker.register_object(
        hook_self.local_worker, obj=self, id=self.id, owners=workers
    )
    for worker in workers:
        # TODO: sync or async? likely won't be worth doing async,
        #       but should check (low priority)
        hook_self.local_worker.send_obj(self, worker)

    hook_self.local_worker.register_object(
        hook_self.local_worker,
        obj=self,
        id=self.id,
        owners=self.owners,
        is_pointer=True,
    )

    return hook_self._var_to_pointer(self, hook_self)


# Traceback (RuntimeError)
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-14-4207de4e45fd> in <module>()
10 loss.backward()
11
---> 12 model.send_(remote)

/Users/atrask/anaconda/lib/python3.6/site-packages/syft-0.1.0-py3.6.egg/syft/core/hooks.py in send_(self, workers)
907                                                    owners=self.owners, is_pointer=True)
908
--> 909             return hook_self._var_to_pointer(self, hook_self)
910
911         setattr(torch.autograd.variable.Variable, 'send_', send_)

/Users/atrask/anaconda/lib/python3.6/site-packages/syft-0.1.0-py3.6.egg/syft/core/hooks.py in _var_to_pointer(self, var, hook_self)
982         print("_var_to_pointer:" + str(var.data.id))
983         if var.grad is not None:
--> 984             self._var_to_pointer(var.grad, hook_self)
985
986         var.data.old_set_(var.data.__class__(0))

/Users/atrask/anaconda/lib/python3.6/site-packages/syft-0.1.0-py3.6.egg/syft/core/hooks.py in _var_to_pointer(self, var, hook_self)
989                                           id=var.data.id,
990                                           owners=var.owners,
--> 991                                           is_pointer=True)
992         return var
993

/Users/atrask/anaconda/lib/python3.6/site-packages/syft-0.1.0-py3.6.egg/syft/core/workers.py in register_object(self, worker, obj, force_attach_to_worker, temporary, **kwargs)
508             raise RuntimeError(
509                 'Invalid registry: is_pointer is {} but owners is {} on tensor {}'.format(
--> 510                     obj.is_pointer, obj.owners, obj.id))
511         # print("setting object:" + str(obj.id))
512         self.set_obj(obj.id, obj, force=force_attach_to_worker, tmp=temporary)

RuntimeError: Invalid registry: is_pointer is True but owners is [0] on tensor 2841986768

# Fixed code
def send_(self, workers):
    """
    Sends a Variable object to a (sequence of) Grid workers.

    Args:
    workers: string (or sequence) containing IPFS address(es)
        of worker node(s).
    """

    # makes singleton if needed
    workers = hook_self.local_worker._check_workers(self, workers)

    # NEW OWNERS: this re-registers the current variable to have new owners!
    #  After this line, self.owners should point to workers (the input variable)
    self = hook_self.local_worker.register_object(
        hook_self.local_worker, obj=self, id=self.id, owners=workers
    )

    for worker in workers:
        # TODO: sync or async? likely won't be worth doing async,
        #       but should check (low priority)
        hook_self.local_worker.send_obj(self, worker)

    # NEW IS_POINTER STATUS. This line changes the is_pointer flag to true.
    hook_self.local_worker.register_object(
        hook_self.local_worker,
        obj=self,
        id=self.id,
        owners=self.owners,
        is_pointer=True,
    )

    return hook_self._var_to_pointer(self, hook_self)