We have seen corruption with the CachedAssetRegistry*.bin files internally on 5.7 and reported by a licensee in 5.6. The corruption seemed to come from multiple UnrealEditor.exe processes, or multiple threads in the same process, attempting to write the files at the same time. The corruption we observed in both cases resulted in the cache being discovered corrupt at load time and discarded, so it does not match your case exactly. But you should try applying the same fix to test whether you’re seeing a different symptom of the same write-collision corruption.
The CachedAssetRegistry*.bin files are created after the AssetRegistry completes its gathering. This happens both when the editor IDE starts and in many commandlets including the cook commandlet.
Please try this code locally and let me know if it prevents further occurrences of the corruption.
Note about the code: In Oct 2025 on 5.7 we encountered on our internal projects the possibility that multiple UnrealEditor.exe would try to save the cache at the same time (e.g. Editor + Commandlet launched from editor). We added A system-wide mutex around the cache file write. If the mutex cannot be entered, we try again later. This was added in these two CLs:
416ad75261e47710bc7533d1f0205c320e7bda90 aka CL 47434330: Writing to the AssetRegistry cache will now attempt to take a system-wide lock…
42e96edc491f0d501bfd39fd0d4de08316911aa2 aka CL 50051915: Avoid possible hang on unix based platforms…
The code used in those changes to retry later if the mutex could not be entered has some complex dependencies on other changes to the AssetDataGatherer in 5.8, so I did not include it. I instead copied just the use of the system-wide mutex. If it cannot be entered, we sleep for 10 seconds, then give an error and abandon the cache write. This will be less robust because it will skip rather than retry, but it will only do that in cases of two editors trying to write at once, which should be infrequent. If you see slow startup in editor or cooker having slow loads, look for this error in the log to see if the mutex is repeatedly failing:
LogAssetRegistry: Error: Timed out trying to write AssetRegistryCacheFiles to %s; another process holds the system-wide mutex \"%s\"
The new code:
Engine\Source\Runtime\AssetRegistry\Private\AssetDataGatherer.cpp:20
#include "HAL/PlatformMutex.h"
Engine\Source\Runtime\AssetRegistry\Private\AssetDataGatherer.cpp:4099
// Line 4099
void FAssetDataGatherer::SaveCacheFile(const TArray<TPair<FName,FDiskCachedAssetData*>>& AssetsToSave)
{
using namespace UE::AssetDataGather::Private;
TRACE_CPUPROFILER_EVENT_SCOPE_STR("Save Cache")
...
// Line 4130
uint64 Hash = CityHash64((const char*)Buffer.GetData(), Buffer.Len() * sizeof(TCHAR));
int32 Index = (Hash & ShardMask);
DataPerShard[Index].Add(Entry);
}
}
// NEW CODE START
// Attempt to get exclusive write access to the cache files. If we cannot, sleep until we can.
// Failing to get the lock here means another process is currently writing. We need to avoid trying to write at the same time to avoid the possiblity of writing corrupted files.
#define CACHEFILE_SYSTEMWIDE_WRITELOCK WITH_EDITOR
#if CACHEFILE_SYSTEMWIDE_WRITELOCK
FString MutexFilename;
{
TStringBuilder<256> Builder;
Builder.Append(*FPaths::Combine(*GGatherSettings.GetAssetRegistryCacheRootFolder(), TEXT("AssetRegistryCacheLock")));
MutexFilename = Builder.ToString();
}
TOptional<UE::FPlatformSystemWideMutex> CacheFilesLock;
CacheFilesLock.Emplace(MutexFilename);
if (!CacheFilesLock->IsValid())
{
CacheFilesLock.Reset();
double StartTime = FPlatformTime::Seconds();
float MaxDurationSeconds = 10.f;
float DisplayDuration = 2.f;
float SleepTimeSeconds = 0.25f;
double NextDisplayTime = StartTime;
for (;;)
{
double CurrentTime = FPlatformTime::Seconds();
float Remaining = static_cast<float>(StartTime + MaxDurationSeconds - CurrentTime);
if (Remaining < 0.f)
{
UE_LOG(LogAssetRegistry, Error,
TEXT("Timed out trying to write AssetRegistryCacheFiles to %s; another process holds the system-wide mutex \"%s\"."),
*GGatherSettings.GetCacheBaseFilename(), *MutexFilename);
return;
}
if (CurrentTime >= NextDisplayTime)
{
NextDisplayTime = CurrentTime + DisplayDuration;
UE_LOG(LogAssetRegistry, Display,
TEXT("Trying to write AssetRegistryCacheFiles to %s, but another process holds the system-wide mutex \"%s\". Sleeping for %.0f more seconds before giving up."),
*GGatherSettings.GetCacheBaseFilename(), *MutexFilename, Remaining);
}
FPlatformProcess::Sleep(SleepTimeSeconds);
CacheFilesLock.Emplace(MutexFilename);
if (CacheFilesLock->IsValid())
{
break;
}
}
return;
}
#endif
// NEW CODE END
// If we recently saved or loaded the file then pause for 0.5 seconds before trying to save on
// top of it, to avoid failure to be able to delete the file we just saved/loaded.
double LocalLastCacheWriteTime;
...
[Attachment Removed]