Take a look at your disenchanter block class:
@Override
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult result) {
if (!world.isRemote) {
TileEntity tileEntity = world.getTileEntity(pos);
if (tileEntity instanceof INamedContainerProvider){
NetworkHooks.openGui((ServerPlayerEntity) player, (INamedContainerProvider) tileEntity, tileEntity.getPos());
} else {
throw new IllegalStateException("Our named container provider is missing.");
}
return true;
}
return super.onBlockActivated(state, world, pos, player, hand, result);
}
If you follow the control flow, the client-side block will always return super.onBlockActivated(state, world, pos, player, hand, result);
The effects you are describing seem to be caused by the client and server following different paths here, the server returning true after opening the gui, and the client returning super.onBlockActivated, which I'm pretty sure defaults to false.