Nav Link Proxy SmartLinkReached event caught by wrong Nav Link

When using NavLinkProxy actors and the Event Received Smart Link Reached, I’ve run into an issue where the wrong NavLinkProxy actor in the world will catch the event. The actor that catches the event is not near the pawn and in fact doesn’t have to be on a nav mesh at all.

Has anyone else seen this?

The PathPt0 is correct, but its CustomLinkId is for the wrong nav link

// handle moving through custom nav links
if (PathPt0.CustomLinkId)
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent(GetWorld());
INavLinkCustomInterface* CustomNavLink = NavSys->GetCustomLink(PathPt0.CustomLinkId);
StartUsingCustomLink(CustomNavLink, SegmentEnd);

INavLinkCustomInterface* UNavigationSystemV1::GetCustomLink(uint32 UniqueLinkId) const
const FNavigationSystem::FCustomLinkOwnerInfo* LinkInfo = CustomLinksMap.Find(UniqueLinkId);
return (LinkInfo && LinkInfo->IsValid()) ? LinkInfo->LinkInterface : nullptr;

Hi . I’ve got the same issue.

It is driving me crazy. I’ve created several different NavLinkProxy classes (in c++ and also in bp) and from them I call specific methods on may AI character to trigger different behaviour.

After 3 days of trying around and debugging I decided to give the reference of the NavLinkProxy to my character and found out, that these are completely wrong.

It is like the character chooses NavLinkProxies which are even not nearby and are even from a completely other subclass of NavLinkProxies.

Have you found any solution for that?

I’ve created some example for my current case.

I have several different NavLinkProxies for different vaulting scenarios in my game.
In this case I positioned the following NavLinkProxy actors in the level


which all directly inherit from AIModule.NavLinkProxy

I furthermore used also blueprint implementations but they seem to have the same issue.

So I placed always 3 of these NavLinkProxies next to each other (by copying them with ALT + drag in the editor).

In some cases the AI uses different ones when running to me, because of a little bit different positioning, so I can try around.

Here is the implementation of the VaultOverObstacle_050_NavLink.

It simply calls a method on my character and it also gives a reference of the current NavLinkProxy to this character. After some testing I saw that this reference is the wrong one!

So I added a print string into the NavLinkProxy…

and even there the NavLinkProxy has sometimes the completely wrong reference.

In my last run the first NavLinkProxy should have been of class VaultOverObstacle_050_NavLink but it was the reference of the last left NavLinkProxy from the first screenshot VaultOverObstacle_200_NavLink3.

This is really a major issue because in this way the NavLinkProxy system is not usable for me.

Sorry, I should have posted the solution we went with. This is in NavigationSystem.cpp. Look for the following line in the RegisterCustomLink function.

// Fix for link id overwriting an existing link id in the CustomLinksMap
while (CustomLinksMap.Contains(LinkId))
LinkId = INavLinkCustomInterface::GetUniqueId();

void UNavigationSystemV1::RegisterCustomLink(INavLinkCustomInterface& CustomLink)
	ensureMsgf(CustomLink.GetLinkOwner() == nullptr || GetWorld() == CustomLink.GetLinkOwner()->GetWorld(),
		TEXT("Registering a link from a world different than the navigation system world should not happen."));

	uint32 LinkId = CustomLink.GetLinkId();

	// if there's already a link with that Id registered, assign new Id and mark dirty area
	// this won't fix baked data in static navmesh (in game), but every other case will regenerate affected tiles 
	if (CustomLinksMap.Contains(LinkId))
		//  Fix for link id overwriting an existing link id in the CustomLinksMap
		while (CustomLinksMap.Contains(LinkId))
			LinkId = INavLinkCustomInterface::GetUniqueId();

		UE_LOG(LogNavLink, VeryVerbose, TEXT("%s new navlink id %u."), ANSI_TO_TCHAR(__FUNCTION__), LinkId);

		UObject* CustomLinkOb = CustomLink.GetLinkOwner();
		UActorComponent* OwnerComp = Cast<UActorComponent>(CustomLinkOb);
		AActor* OwnerActor = OwnerComp ? OwnerComp->GetOwner() : Cast<AActor>(CustomLinkOb);

		if (OwnerActor)
			ENavLinkDirection::Type DummyDir = ENavLinkDirection::BothWays;
			FVector RelativePtA, RelativePtB;
			CustomLink.GetLinkData(RelativePtA, RelativePtB, DummyDir);

			const FTransform OwnerActorTM = OwnerActor->GetTransform();
			const FVector WorldPtA = OwnerActorTM.TransformPosition(RelativePtA);
			const FVector WorldPtB = OwnerActorTM.TransformPosition(RelativePtB);

			FBox LinkBounds(ForceInitToZero);
			LinkBounds += WorldPtA;
			LinkBounds += WorldPtB;

			AddDirtyArea(LinkBounds, FNavigationOctreeController::OctreeUpdate_Modifiers);

	CustomLinksMap.Add(LinkId, FNavigationSystem::FCustomLinkOwnerInfo(&CustomLink));
1 Like

Oh nice. I’ll check this out. Thx :slight_smile:

this issue has been causing me grief for some time, fortunately I may have found a practical workaround for this - as the issue is essentially due to the ID of the navlinks being incorrect or duplicated you can try the following to give them all new IDs (I assume):

  • finish your placement/arrangement of your various navlinks
  • save the level and close the editor
  • re-open the editor and load the level
  • use the World Outliner search to filter down to all your NavLinkProxy actors placed in the level
  • select them all at once
  • delete them all at once
  • undo your delete

as far as I can tell this effectively ‘refreshes’ the IDs of your navlinks and seems to solve the problem

not certain if this works 100% but seems to solve it in my case, will update if I find out any more on this

I also raised a bug report for this referencing this thread, and there is a pull request which appears to aim at fixing this problem also:

1 Like

Hi everyone,

Another user tipped me off about this thread concerning NavLink ID mismatch. An official fix has been committed last month. Here is a direct link to it:

If you build from source, this should fix the issue as we have moved from an incremental int to using a 64-bit city hash for the ID. If you are waiting for a Epic Games Launcher build, it will be included in 5.3.


the issue is still open on github - wondering if it got included or not in 5.3 as said above. thanks for this info about navlinks.

The fix was included as part of 5.3. I do not know what issue may be showing as open still on GitHub, but the NavLink IDs have been changed over to the 64-bit hash.