UActorChannel::ReadContentBlockHeader: Sub-object not in parent actor 1. SubObj:

So I have actor, which have setup custom replication for subobjects and it looks like this:

UCLASS(BlueprintType, Blueprintable)
class GAMEINVENTORYSYSTEM_API AGISPickupActor : public AActor
{
	GENERATED_UCLASS_BODY()
public:
	UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Instanced)
		TArray<class UGISItemData*> ItemToLoot;


	virtual bool ReplicateSubobjects(class UActorChannel *Channel, class FOutBunch *Bunch, FReplicationFlags *RepFlags) override;
	virtual void GetSubobjectsWithStableNamesForNetworking(TArray<UObject*>& Objs) override;
}


bool AGISPickupActor::ReplicateSubobjects(class UActorChannel *Channel, class FOutBunch *Bunch, FReplicationFlags *RepFlags)
{
	bool WroteSomething = Super::ReplicateSubobjects(Channel, Bunch, RepFlags);

	for (const UGISItemData* SlotItem : ItemToLoot)
	{
		if (SlotItem)
		{
			WroteSomething |= Channel->ReplicateSubobject(const_cast<UGISItemData*>(SlotItem), *Bunch, *RepFlags);
		}
	}
	return WroteSomething;
}
void AGISPickupActor::GetSubobjectsWithStableNamesForNetworking(TArray<UObject*>& Objs)
{
	for (const UGISItemData* SlotItem : ItemToLoot)
		{
			if (SlotItem)
			{
				Objs.Add(const_cast<UGISItemData*>(SlotItem));
			}
		}
}

Nothing out of ordinary.

And now I try to get items from ItemToLoot array with function in component:

void UGISInventoryBaseComponent::LootItems(class AGISPickupActor* LootContainer)
{
	if (GetOwnerRole() < ROLE_Authority)
	{
		ServerLootItems(LootContainer);
	}
	else
	{
		if (!LootContainer)
			return;

		LootContainer->SetOwner(GetOwner());

		for (UGISItemData* Item : LootContainer->ItemToLoot)
		{
			AddItemToInventory(Item);
		}
	}
}

Function is called from server.

And I get these errors:

[401]LogNetTraffic:Error: UActorChannel::ReadContentBlockHeader: Sub-object not in parent actor 1. SubObj: ARItemInfo_4, Actor: MyCharacter_C_1
[2014.12.14-22.46.46:565][401]LogNet:Error: UActorChannel::ReceivedBunch: ReadContentBlockHeader FAILED. Bunch.IsError() == TRUE.  Closing connection.
[2014.12.14-22.46.46:565][401]LogNet: UNetConnection::Close: Name: IpConnection_0, Driver: GameNetDriver IpNetDriver_1, PC: MyPlayerController_C_1, Owner: MyPlayerController_C_1, Channels: 9, RemoteAddr: 127.0.0.1:7777, Time: 2014.12.14-22.46.46
[2014.12.14-22.46.46:566][401]LogNet: UChannel::Close: Sending CloseBunch. ChIndex == 0. Name: ControlChannel_0
[2014.12.14-22.46.46:566][401]LogNetTraffic:Error: UChannel::ReceivedRawBunch: Bunch.IsError() after ReceivedNextBunch 1
[2014.12.14-22.46.46:566][401]LogNet:Warning: Network Failure: GameNetDriver[ConnectionLost]: Your connection to the host has been lost.
[2014.12.14-22.46.46:566][401]LogNet: NetworkFailure: ConnectionLost, Error: 'Your connection to the host has been lost.'

And I honestly at this point, don’t know what I’m doing wrong.

Here is replicated object:

Thanks to some pondering on IRC I finally learned what the issue was, and it’s actually quite funny.

So the problem was that I tried to copy pointers from

TArray<class UGISItemData*> ItemToLoot;

Which is in one actor, to essentially another actor. And that other actor tried to replicate objects, to which those pointers… well pointed. It if course couldn’t work.

The solution to it, is to either reconstruct entire array if the another actor, or just reconstruct items one by one, when we add them.

Whichever you choose you do it like this:

			UGISItemData* test = ConstructObject<UGISItemData>(Item->GetClass(), this, NAME_None, RF_NoFlags, Item);

First parameter is going to be class, second and third parameters are not that important and you can read about them in documentation, fourth parameter is original object from which we want to copy values.

So it is important class is also determined from the same object, otherwise you might end up with different class layout and crash ;).

I had exactly this problem, thanks so much for posting your findings!

Thanks mate! This was very helpful