Repository navigation
Investigate native allocator lifetime failures during scene cleanup #393
Description
DISCLOSURE: LLM-GENERATED TEXT
Later observation — 2026-10-18: the separately registered campaign 39132725629, source d32549a0153429a3e1b7ae65db07b65b4c2f18e7, passes the SINGLE_THREADED Standalone job. Its verified artifact 12139248791 is 858,528 bytes, SHA256 39252247927601449c2cdfa1719440b8dde2d78ee5053b6d6b4a8e52627cd547. XML records 18,383 total / 16,628 passed / zero failed / 23 inconclusive / 1,732 skipped, root Skipped:Ignored. The previously affected LoadedSceneRetrievalBorrowsActiveAndNonactiveScenes(True,7) passes with seed 983445584. This adds a passing observation without identifying the allocation owner or repairing the original occurrence. No warning suppression, retry or scene-helper source fix is claimed; cause and remaining acceptance stay open.
Current scope and acceptance
The allocator lifetime warning is still an unresolved failure. It occurs across scene fixtures and Unity versions; its native allocation origin is not established. A passing run elsewhere does not prove the warning harmless or classify the cause. Preserve unexpected-warning assertions while investigating.
New retained recurrence — 2026-10-18: campaign 39125782708, SINGLE_THREADED job 117670565816, source bc6511cc86a75dc5a7c44929284a0f8f8438313d, fails Standalone SceneHelperLifetimeTests.LoadedSceneRetrievalBorrowsActiveAndNonactiveScenes(True,7) in TearDown. The case seed is 876965602, with zero retry/repeat iterations. XML totals: 18,383 / 16,627 passed / one failed / 1,732 skipped / 23 inconclusive. Verified artifact 12137120952 SHA256: b3a9c5e1994dbfc0f4d620159aee1e8d17a78814ebea0add0f55bd5d86303871.
The complete player log records four allocator lifetime warnings with ages 10, 11, 6, 6; the failed case reports age six against a four-frame allowance. No allocation-origin stack is retained. The actual player command omits -diag-job-temp-memory-leak-validation; XML sibling order and second-resolution timestamps do not establish which preceding operation allocated the memory. This case creates an already-loaded scene, so the helper scopes borrow synchronously; the common test teardown performs its unload. Do not attribute this recurrence to the helper owned-load/unload path without evidence. Configure/build report counters contain no crash headers, while license cleanup and lock release are healthy; those observations do not resolve the lifetime error. No retry, warning suppression or source change was used to make this occurrence pass. Next: a controlled allocation-diagnostics reproduction using the existing runner flag, with allocation-origin evidence and matching direct SceneManager/helper lifecycle controls. The cause and full acceptance remain open.
PR #1025 retains another occurrence on commit 2c9784a6: Unity 6000.6 job 117548232907, Standalone SceneHelperTests.GetAllObjectsOfTypeInSceneReturnsEmptyWhenTypeMissing, TearDown, permitted lifetime 4 frames / age 5. The verified artifact and result counts are retained. The failure has no allocation-origin stack. The scene helper awaits load and owned-scene unload; its fixture tracks asynchronous disposal. Those facts locate the affected lifecycle but do not identify the allocation owner.
The single same-head repeat passes, including the previously failed scene case, with confirmed healthy cleanup. PR #1025 was merged as 5b025285 after current-head checks passed. The original failure remains unresolved; no source or warning assertion changed for the repeat. Verified repeat artifact 12121704400 has SHA256 5f81c2d274e0265d20b87057570528b75b1deb5246723bed5296676a07279a56 and Standalone totals 18,394 / 16,639 passed / zero failed / 1,732 skipped / 23 inconclusive. The distinct Editor build access-violation exit remains on #343. A successful repeat is additional evidence, not a lifetime fix.
Remaining acceptance:
- Obtain the native allocation origin and correlate it with scene load, unload, and fixture cleanup. Separate a package lifetime bug, test isolation bug, and engine defect using evidence.
- Implement a fix for the identified mechanism. Preserve unexpected warnings and the scene behavior assertions; do not add retries or ignore rules to turn an unexplained warning green.
- Verify the affected Standalone configurations and retain failed reports alongside later evidence. A passing rerun alone does not resolve this issue.
Historical report
The original report below records the earlier hypothesis and proposed options. Its claims that the warning is harmless or exclusively due to machine load are not established, and its suppression proposals are not an accepted fix.
Symptom
RelationalComponentsZenjectTests.SceneInitializerUsesMultiPassWhenConfigured fails in TearDown,
never in the body:
TearDown : Unhandled log message: '[Warning] Internal: deleting an allocation that is older than
its permitted lifetime of 4 frames (age = 6)'. Use UnityEngine.TestTools.LogAssert.
That warning comes from Unity's native temp allocator, not from any code in this repository. It
fires when a temp allocation outlives four frames, which depends on how many frames elapse while the
scene initializes — i.e. on machine load, not on logic.
Why it is a fragile check rather than a defect
Observed on run 31390509089,
6000.5.2f1 standalone on DAD-MACHINE. In the same run, the same test passed on
2022.3 standalone, 6000.3 standalone and 6000.5 playmode, each with zero leg failures. Same
commit, same code, same editor family — so nothing about the test's subject changed between the leg
that failed and the three that passed.
The test does not assert anything about allocator lifetimes. It fails because Unity's test framework
treats any unexpected log message as a failure, and this particular warning is emitted
nondeterministically by the engine during scene setup.
Options
- Expect it where it can occur.
LogAssert.ignoreFailingMessages = truefor the duration, or a
targetedLogAssert.Expect(LogType.Warning, new Regex("permitted lifetime")). Targeted is better
— blanket ignoring would also swallow a real warning this test should catch. - Reduce the frame count during initialization, if the multi-pass path is holding a temp
allocation across more frames than it needs to. Worth a look before suppressing: the warning is
pointing at something real even if it is not a test failure. - Shared handling. If other scene-initialization tests can hit the same warning, the expectation
belongs in the common fixture base rather than in one test.
Option 2 first — the warning names a real lifetime, and suppressing it without looking would be
treating the symptom. If the lifetime turns out to be inherent to how Unity schedules scene
initialization, then option 1, targeted.
Not to be confused with
#392 — that one fails before
any test runs and uploads no results.xml. This one has a full results.xml with 8,967 cases and
exactly one failure, which is how the two are told apart in ten seconds: if the artifact has a
results.xml, repository code ran and it is not an infrastructure failure.
Activity
wallstop commentedon Aug 11, 2026
Hit again on PR #409, and on a different, unrelated fixture — which settles the diagnosis and
changes which of this issue's three options is right.
Run
31465329995,6000.3.16f1 standalone. Fifteen of the sixteen Unity legs on that same commit passed, includingthe other three IL2CPP standalone legs and every editmode and playmode leg.
results.xmlis presentwith exactly this one failure, so by this issue's own ten-second test it is repository code failing,
not infrastructure.
Option 2 is now ruled out.
RuntimeSingletonTests.InstanceComponentIsEnabledenables a componenton a singleton; it initializes no scene and holds no temp allocation, so there is no frame count to
reduce. The warning is not pointing at anything this repository does — it is Unity's native temp
allocator reacting to how many frames elapsed, which is machine load.
Option 3 is now the indicated one, and more broadly than it was written: the expectation does not
belong in "scene-initialization tests", because this fixture is not one. Any test whose teardown can
straddle a slow frame can hit it, so the handling belongs wherever unhandled-log strictness is
configured for the runtime suites as a whole.
The awkward part worth stating up front for whoever takes it:
LogAssert.Expectis the wrong tool,because it requires the message to appear and this one appears nondeterministically. That leaves
LogAssert.ignoreFailingMessagesscoped as narrowly as possible, which is blanket within its scope —so the scope, not the pattern, is what has to be argued. That is a global change to test strictness
across the runtime suites and cannot be verified in the devcontainer at all (
Tests/Runtimeis aPlayMode assembly and the MCP bridge cannot run PlayMode), so it wants its own change with the full
matrix behind it rather than being folded into an unrelated PR.
wallstop commentedon Aug 20, 2026
Investigated both options the issue proposes. Option 2 has no target, and Unity has no API for
option 1 as written.
Option 2: there is no temp allocation to shorten.
RelationalComponentSceneInitializer.Initializeis straight-line synchronous —
rg -n 'yield return|IEnumerator|Coroutine' Runtime/Integrations/returns nothing — and the multi-pass branch's only engine call,
FindObjectsOfTypeShim, returns amanaged
Object[]. Everything else there is a pooled managed collection. Repository-wide there iszero
Allocator.Temp,Allocator.TempJob,NativeListorNativeHashMap; the onlyUnity.Collectionsuse anywhere isGetRawTextureData<T>inColorExtensions, synchronous andunrelated. The test's
yield return nullhappens afterInitialize()has fully returned, sonothing the production code allocates can outlive the call, let alone four frames.
The warning comes from the engine during
CommonTestBase's multi-frame teardown, which pumps frameswith an
UnloadSceneAsyncin flight (CreateTempSceneregisters it as tracked async disposal).Four fixtures can reach it, all through the same
LogAssert.NoUnexpectedReceived()atTests/Core/CommonTestBase.cs:641, which is PlayMode-gated:RelationalComponentsZenjectTests,RelationalComponentsVContainerTests(which has a structurally identical multi-pass test),RelationalComponentsReflexTestsandSceneHelperTests. So a per-test expectation would have to bepasted into four places and would rot on the fifth — the fix belongs in the base, as option 3 says.
But
LogAsserthas no tolerate-if-present API. Enumerated in a live Unity6000.4.6f1, itsentire public surface is:
Which rules out both of the issue's option-1 forms:
LogAssert.Expect(LogType.Warning, new Regex("permitted lifetime"))is mandatory-match. Thewarning is nondeterministic — it passed on three of four legs in the cited run — so expecting it
inverts the flake: the test then fails on every leg where the warning does not appear.
ignoreFailingMessages = trueis blanket, andCommonTestBase.cs:1103-1104already records whythat was rejected: it masks genuine regressions.
ExpectErrorcannot see this message at all. ItsExpectedErrorSuppressingHandlersits onDebug.unityLogger.logHandler, which only intercepts managedDebug.Log*calls; this is a nativelog that reaches
LogAssertwithout passing through it. Using it here would suppress nothing andthen fail teardown as "never matched".
That leaves one implementable option: reflect into
UnityEngine.TestTools.Logging.LogScope.Currentand drop matching entries from
FailingLogsbeforeNoUnexpectedReceived(). It is an internal UTFtype, so it is fragile across Test Framework versions, and it would sit in the base class every
fixture inherits — which is why I have not shipped it unilaterally. If you want it, it should be
guarded so that a failed lookup falls through to today's behaviour rather than silently passing.
Order a name no integer can hold, refuse a run that verified nothing,…
wallstop commentedon Aug 26, 2026
RCA, and a fix that was built, measured, shipped to CI, and reverted
The failure site is this repository's own guard
CommonTestBase.UnityTearDowncallsLogAssert.NoUnexpectedReceived()in PlayMode as across-test log-pollution guard. Measured on 6000.4.6f1: a bare
[Warning]inside aLogScopefails that call with
UnhandledLogMessageException. So the engine's temp-allocator warning doesnot need to be an error to redden the test; any warning at all does.
Option 2 in this issue is refuted
The issue proposes looking first at whether the multi-pass path holds a temp allocation longer than
it needs to. It holds none. There is no
Allocator.Temp,NativeArray,NativeListorTempJobon any path the test touches; the only native allocations anywhere in
Runtime/aretexture.GetRawTextureData<T>()inColorExtensions. The warning is the engine's own scenemachinery, and nothing in this repository can shorten its lifetime.
What was built
A tolerance that is not
ignoreFailingMessages: count the engine messages that arrive while theframework's own per-test scope is open, then register exactly that many
LogAssert.Expectexpectations before the guard runs. Six properties were measured on 6000.4.6f1 to make that safe:
[Warning]failNoUnexpectedReceived?UnhandledLogMessageExceptionExpectmatch a log already recorded?UnexpectedLogMessageExceptionat end of scopeignoreFailingMessageschange retroactive matching?Against the 6000.4.6f1 editor the fixture ran 10/10 and the protocol fixture 16/16.
Why it was reverted
The retroactive property is not universal. On
2021.3.45f1PlayMode, CI failed on the veryfixture that proves the mechanism:
The expectation was registered for a message that had demonstrably arrived -- the handler counted
it -- and that Test Framework version did not reconcile it. That turns a warning which sometimes
fails a test into one that always does. Worse than the flake.
So the finding to carry forward is a constraint, not a fix: no fix for this issue may depend on
LogAssert.Expectsemantics, because this package ships across four editor versions and thatbehaviour differs between them. It is the same class as
#553: a confident answer from
one editor for a question that is resolved out of Unity's own implementation.
What is left for whoever takes it
Of the issue's own options, 1 and 3 survive:
LogAssert.ignoreFailingMessages = truescoped as narrowly as the fixture allows. Blunt, and theissue is right that it swallows real warnings, but it is version-independent.
LogAssert.Expectinside the one fixture, accepting that it fails when the warningdoes not appear -- which on the evidence is most of the time, so this is not viable alone.
NoUnexpectedReceived()guard with one built on this repository's ownApplication.logMessageReceivedThreadedrecord, which is the only route that owns its ownsemantics across editors. That is a larger change than this issue is worth on its own, but it is
the one that would work.
Frequency, for whoever prices those: one leg of one run
(31390509089),
with the same commit green on
2022.3 standalone,6000.3 standaloneand6000.5 playmode.Revert the tolerated-engine-log reconciliation
wallstop commentedon Aug 26, 2026
Option 1's cheaper half is eliminated too, measured
Follow-up to the RCA above, because the obvious next idea after "targeted
Expectis notversion-portable" is "then just set
ignoreFailingMessageswhen the tolerated warning shows up".It does not work. Measured on 6000.4.6f1, driving a real
LogScopewith a control:UnhandledLogMessageException-- the probe can see a failureLogAssert.ignoreFailingMessages = trueUnhandledLogMessageExceptionFalseThe flag is consulted when a log is added to the failing set, not when the set is evaluated. By
the time anything in this repository can react to the warning, it is already recorded, and nothing
set afterwards removes it.
So the option list is now:
targeted-- works on 6000.4, not on 2021.3 (above).LogAssert.Expectafter the fact-- works on no editor; measured.ignoreFailingMessagesafter the factignoreFailingMessages = truebefore the warning can arrive, i.e. for the whole PlayModetest. This is the only lever that works, and it is the blanket suppression this issue explicitly
rejected: it would disable unexpected-log detection across the entire PlayMode suite, including
the cross-test pollution guard
CommonTestBasewas built to provide.Application.logMessageReceivedThreadedrecord, so the semantics are ours rather than the TestFramework's. This is the only route that both fixes the flake and keeps the guard, and it is a
larger change than one nondeterministic warning justifies on its own -- but it is the answer if
the warning starts appearing on more than one leg of one run.
Recorded so the next attempt starts from three eliminated options rather than repeating them.
Strict UTF-8 decode, test-flake fix, docs sweep (Ambiguous-Interactiv…
wallstop commentedon Oct 17, 2026
DISCLOSURE: LLM-GENERATED TEXT
Reproduced during session closeout in run 39007855641, job 117323949587, head
7508f55a, Unity 6000.6.0f1 Standalone.SceneHelperTests.GetObjectOfTypeInScenefails only in TearDown on the native warningInternal: deleting an allocation that is older than its permitted lifetime of 4 frames (age = 5). The player log also contains age=6. XML reports 18,302 cases: 16,546 passed, one failed, 1,732 skipped, 23 inconclusive. There are no native crash headers in the full job log; license cleanup and lock release are confirmed healthy.Artifact
12092951328is bound to this run/head. Downloaded ZIP SHA-256 is97666be37dda368f3b9917767e7e310dcb3faa6d68ee4f62d1e83ba4f34f5b5b. XML identifies exactly this teardown warning, with no assertion failure or managed stack trace. All Runtime/Editor/test C# and analyzer inputs are unchanged from mainc5ce8ed4; #1020 changes CI scripts and documentation only.The #586 fix leaves the native path uncovered:
Tests/Core/CommonTestBase.cs:304seeds a tolerated warning inExpectedErrorSuppressingHandler, which handles managed logger calls, whileUnityTearDownstill callsLogAssert.NoUnexpectedReceived()at line 697. The previous investigations above already explain why native engine logs bypass that handler and why retroactive expectations and blanket suppression are unsuitable. The current artifact shows the exact class remains possible after the issue was closed.Reopening this defect. A current-head retry of only the failed normal CI job can qualify the affected tooling PR's checks; it does not fix this warning or close this investigation. Per the user's wrap-up instruction, no broader test-framework implementation, warning suppression, or new native experiment is being started. Acceptance remains a native-log-aware guard that preserves unrelated unexpected-log failures across supported editor versions.
wallstop commentedon Oct 17, 2026
DISCLOSURE: LLM-GENERATED TEXT
The unchanged-head single-job retry passes. Its fresh Standalone artifact
12093684375, created 07:54:35 UTC in run39007855641, matches SHA-2565a616190a71ecae2cc8549deac7cf42df98d476d9b13721b325a83e117c59229. XML reports 18,302 total, 16,547 passed, zero failed, 1,732 skipped and 23 inconclusive;SceneHelperTests.GetObjectOfTypeInSceneexplicitly passes. The original failed artifact12092951328remains retained and its checksum is recorded above.This demonstrates another successful execution, not a fix for the native warning or the test guard. No code, warning filter, or test selection changed. NUnit seeds differ between the two normal executions. This issue stays open.
wallstop commentedon Oct 17, 2026
DISCLOSURE: LLM-GENERATED TEXT
The same native allocator warning recurred in #1022 Unity 6000.5 job 117345529671, unchanged head
27743eeb. This time the failed case isSceneHelperLifetimeTests.LoadedSceneRetrievalBorrowsActiveAndNonactiveScenes(False,7), again in TearDown, with lifetime=4 frames and age=14. No Runtime/Editor/test C# or analyzer inputs differ from main. Full-log inspection shows no native crash headers and confirms healthy license cleanup and lock release.Fresh failed artifact
12094819473is bound to this run/head. The ZIP was downloaded and byte-verified against SHA-256157f0e4dec0d41c796b5457a46c04ec26e03a1b3963eb91c091711fa807a4638; XML identifies exactly one failed case and the warning above. This is additional evidence that the shared native-log guard defect remains open across fixtures and Unity versions. No warning suppression or harness implementation is being added during closeout. The single failed normal leg can be retried only once the containing workflow's remaining Unity 2022 job finishes; such a retry will not close this issue.wallstop commentedon Oct 17, 2026
DISCLOSURE: LLM-GENERATED TEXT
The unchanged-head Unity 6000.5 retry also passes. Its fresh Standalone artifact
12095573638, created 09:06:24 UTC in run39007870117, matches SHA-256ec83814fb66b56d7285ebb4faa076873f343bc34d5efd8d2433a74763774f110. XML reports 18,302 total, 16,547 passed, zero failed, 1,732 skipped and 23 inconclusive; the previously failedSceneHelperLifetimeTests.LoadedSceneRetrievalBorrowsActiveAndNonactiveScenes(False,7)case explicitly passes. The original failed artifact and checksum remain retained above.NUnit seeds differ between the two normal executions. No source, test selection, or warning policy changed. This adds successful-execution evidence; it does not fix the native warning or its test guard. This issue remains open.
wallstop commentedon Oct 18, 2026
DISCLOSURE: LLM-GENERATED TEXT
The allocator lifetime warning recurred on PR #1025 head
492b61fc5869d01daa1a88d3dab80039980355be, SINGLE_THREADED Unity 6000.6 job 117502936658. Standalone XML reports 18,187 total, 16,431 passed, one failed and 1,732 skipped. The failure isSceneHelperTests.GetObjectOfTypeInScenein TearDown: a native allocation exceeded its four-frame lifetime (age 7). The final mode verifier and aggregate correctly fail; the license cleanup and lock-release steps succeed.This is another affected scene fixture, not evidence that the warning is harmless or fixed. No assertion or warning policy has been weakened. The original failed run remains available while subsequent protobuf and rule-snapshot changes are developed for the same PR.
wallstop commentedon Oct 18, 2026
DISCLOSURE: LLM-GENERATED TEXT
The same allocator-lifetime warning recurred on PR #1025 head
2c9784a63ae1b6286678d8d2adf751ed3920313d, regular Unity 6000.6 job 117548232907. Its sole failed case isSceneHelperTests.GetAllObjectsOfTypeInSceneReturnsEmptyWhenTypeMissing, in TearDown: a native allocation exceeded the four-frame lifetime (age 5). The test body checks an empty result after scene loading; its tracked disposal unloads the owned scene. The report contains no allocation-origin stack, so this identifies the observed lifetime failure, not its native cause.Failed Standalone artifact 12120886610 is bound to this run/head and independently matches SHA-256
053711a5005c45cd74f182980eec8c90f04150e7b25184ffe2213feb9d98ff11. XML reports 18,394 total: 16,638 passed, one failed, 1,732 skipped and 23 inconclusive. EditMode and PlayMode report zero failures, and WProto-only Standalone passes 82/82. License cleanup and lock release are confirmed healthy.No scene assertion or native-warning policy was weakened. The other matrix jobs are still running. Any later successful execution will be additional evidence, not a fix or closure of this issue.
[-]test: a Zenject scene test fails on Unity's temp-allocator lifetime warning, nondeterministically[/-][+]Investigate native allocator lifetime failures during scene cleanup[/+]Freeze WProto inputs after scene preparation