CastChecked<UPCGComponent>(nullptr) crashes inside the PCG grid-linkage element when a partitioned, runtime-generated component executes a cross-grid linkage while its Original component is torn down concurrently. The first fetch of the Original is ensure-guarded; a second, unguarded re-fetch inside GetLocalSource() uses CastChecked and dies when the Original has become null in between. (Full symbolized call stack is in Steps to Reproduce / attached log.)
FATAL ERROR
[File: …\CoreUObject\Private\Templates\Casts.cpp] [Line: 10] Cast of nullptr to PCGComponent failed
Crash frame: FPCGComponentExecutionState::GetLocalSource() (PCGComponentExecutionState.cpp:198), called from PCGGraphExecutor::ExecuteGridLinkage() (PCGGraphExecutor.cpp:3606), on a task worker thread.
ROOT CAUSE (line numbers are 5.8)
In PCGGraphExecutor.cpp, the “retrieve” branch of ExecuteGridLinkage:
3595 OriginalSource = ExecutionState.GetOriginalSource();
3596 if (!ensure(OriginalSource)) return false; // FIRST fetch - guarded
3606 ExecSourceWithData = ExecutionState.GetLocalSource(…); // re-fetches Original, UNGUARDED
3609 if (!ExecSourceWithData) return true; // null LOCAL source handled gracefully
GetLocalSource (PCGComponentExecutionState.cpp:198) then does:
CastChecked<UPCGComponent>(GetOriginalSource()) // CastChecked(nullptr)
GetOriginalSource() -> Component->GetOriginalComponent(), which for a local component resolves through the partition actor (PCGPartitionActor.cpp:452):
const TSoftObjectPtr<UPCGComponent>* Orig = LocalToOriginal.Find(LocalComponent);
return Orig ? Orig->Get() : nullptr; // null if entry removed OR soft-ptr target destroyed/unloaded
So the Original resolves to null when, between line 3596 and line 198, the Original component is destroyed / unregistered / removed from LocalToOriginal (or its TSoftObjectPtr target is GC’d/unloaded). This coincides with the runtime-gen scheduler’s continuous teardown (“aborted after cleaning up N/83 components”) on another thread while the linkage task runs on a worker thread.
The asymmetry is the bug: the first Original fetch is ensure-guarded (3596) and a null LOCAL source is handled gracefully (3609), but the second Original fetch (line 198) is an unguarded CastChecked, reachable with a null Original whenever teardown races linkage execution.
EVIDENCE
The same session first logged the corresponding handled ensure (“Ensure condition failed: OriginalSource [PCGGraphExecutor.cpp] [Line: 3596]”, worker thread), then ran ~12 min before the fatal CastChecked at line 198. Both occur on worker threads during heavy FPCGRuntimeGenScheduler cleanup, right after the player crossed a chunk boundary.
SUGGESTED FIX
1) Make line 198 tolerant of a null Original, mirroring the graceful null-local-source handling at 3609 - reuse the already-validated OriginalSource from 3595, or replace CastChecked with Cast + early-out instead of asserting.
2) Cancel/drain in-flight grid-linkage tasks for a local component before its Original is removed from LocalToOriginal or destroyed during runtime-gen cleanup.
WORKAROUND
pcg.GraphMultithreading 0 (linkage runs on game thread, removing the cross-thread window); reducing runtime-gen churn (larger frame time budget / smaller generation radii) also narrows it.
Full logs and a minidump available on request.
[Attachment Removed]