#9872·carla

Walker navigation is permanently dead on a level with an unbuilt `RecastNavMesh`

Author: M-ColleyCreated Sep 4, 2026Updated Sep 9, 2026

Describe the bug

UCarlaNavigationSubsystem::HasServerSideNavigation() reports that the server can serve navigation whenever the default nav data is an ARecastNavMesh whose HasValidNavmesh() is true:

cpp
// Carla/Navigation/CarlaNavigationSubsystem.cpp
const ARecastNavMesh *NavMesh =
    Cast<ARecastNavMesh>(NavSys->GetDefaultNavDataInstance());
return (NavMesh != nullptr) && NavMesh->HasValidNavmesh();

HasValidNavmesh() only means a dtNavMesh object exists and has been sized. It is true for a navmesh holding zero tiles — which is the state of any level that ships a RecastNavMesh actor whose data was never built, or whose tiles have not streamed in yet.

That answer then travels to the client over is_navigation_server_side, and the client has no way back:

cpp
// LibCarla/source/carla/client/detail/Simulator.cpp
if (nav->IsServerSide()) {
  for (int i = 0; i < 3; ++i) {
    auto location = _client.GetRandomLocationFromNavigation();
    if (location.z > -9.0e5f) return location;
  }
  return {};                       // <-- no fallback to the client-side path
}
return nav->GetRandomLocation();   // <-- never reached

So the entire client-side navigation path — including any Saved/Nav/<MapName>.bin the user has built with RecastBuilder — becomes unreachable, and FNavigationMesh::Load is never called. Every walker API fails silently: get_random_location_from_navigation() returns None, walkers cannot be placed, and nothing is logged at any verbosity.

Steps to reproduce

  1. Load any level that has a RecastNavMesh actor with no built tiles (a World Partition level whose navmesh has not been built is the easy case).
  2. Place a valid CARLA navmesh at Saved/Nav/<MapName>.bin.
  3. world.get_random_location_from_navigation()None, every time.

Expected

Either the server serves navigation, or the client falls back to the navmesh it can load itself. A .bin sitting in Saved/Nav/ should not be ignored because an empty RecastNavMesh claimed the job first.

Actual

Neither path runs. The failure is silent and looks identical to "no navmesh was ever built".

Suggested fix

Test the property that actually matters — that there are polygons to navigate on — rather than that a navmesh object exists. One sample answers it, and this runs once per client:

cpp
FNavLocation Probe;
if (!NavSys->GetRandomPoint(Probe, NavSys->GetDefaultNavDataInstance()))
{
  UE_LOG(LogCarla, Warning,
         TEXT("Navigation: '%s' has a valid navmesh object but no reachable "
              "polygons - falling back to the client-side navmesh"),
         *NavMesh->GetName());
  return false;
}
return true;

Worth logging the chosen branch either way: which of the two navigation systems is live is currently invisible from both sides.

Environment

  • CARLA ue58-dev-carla @ de3f38e64, running Epic's City Sample