# Buggy code
def deser(self, obj_msg):
    if "data" in obj_msg.keys():
        data_msg = json.loads(obj_msg["data"])
        tensor_type = hook_self.types_guard(data_msg["torch_type"])
        data_obj = tensor_type.deser(tensor_type, data_msg)
        # data_obj = hook_self.build_tensor(data_msg, tensor_type)
        data = hook_self.local_worker.handle_register(data_obj, data_msg)

    if "grad" in obj_msg.keys():
        if obj_msg["grad"] is not None:
            grad_msg = json.loads(obj_msg["grad"])
            var_type = hook_self.types_guard(grad_msg["torch_type"])
            grad_obj = hook_self._build_var(grad_msg, var_type)
            grad = hook_self.local_worker.handle_register(
                grad_obj, grad_msg, force_attach_to_worker=False, temporary=True
            )

        else:
            grad = None
    var = self(
        data, volatile=obj_msg["volatile"], requires_grad=obj_msg["requires_grad"]
    )
    # var.grad = grad
    if grad is not None:
        setattr(var, "grad", grad)
    else:
        var.grad = None

    # this returns grad because garbage collection seems to do something really strange
    # if grad isn't returned here. It re-initializes the gradient somehow but in a way
    # where it's not registered (which is bad)
    return var


# 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 deser(self, obj_msg):
    """Deserializes a JSON object into a variable"""

    if "data" in obj_msg.keys():
        data_msg = json.loads(obj_msg["data"])
        tensor_type = hook_self.types_guard(data_msg["torch_type"])
        data_obj = tensor_type.deser(tensor_type, data_msg)
        # data_obj = hook_self.build_tensor(data_msg, tensor_type)
        data = hook_self.local_worker.handle_register(data_obj, data_msg)

    if "grad" in obj_msg.keys():
        if obj_msg["grad"] is not None:
            grad_msg = json.loads(obj_msg["grad"])

            var_type = hook_self.types_guard(grad_msg["torch_type"])
            grad_obj = hook_self._build_var(grad_msg, var_type)

            grad = hook_self.local_worker.handle_register(
                grad_obj, grad_msg, force_attach_to_worker=False, temporary=True
            )
        else:
            grad = None

    # nn.parameter.Parameter does not accept "volatile" as an input param.
    # https://pytorch.org/docs/0.3.1/autograd.html#variable
    if self == torch.nn.parameter.Parameter:
        var = self(data, requires_grad=obj_msg["requires_grad"])
    else:
        var = self(
            data, volatile=obj_msg["volatile"], requires_grad=obj_msg["requires_grad"]
        )

    # var.grad = grad
    if grad is not None:
        setattr(var, "grad", grad)
    else:
        var.grad = None

    # this returns grad because garbage collection seems to do something really strange
    # if grad isn't returned here. It re-initializes the gradient somehow but in a way
    # where it's not registered (which is bad)
    return var