{"record":{"id":"4ad71522472daa15","repo":"emberjs/ember.js","slug":"attempted-to-assert-destroyables-destroyed-but-yo","errorCode":null,"errorMessage":"Attempted to assert destroyables destroyed, but you did not start a destroyable test. Did you forget to call `enableDestroyableTracking()`","messagePattern":"Attempted to assert destroyables destroyed, but you did not start a destroyable test\\. Did you forget to call `enableDestroyableTracking\\(\\)`","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@glimmer/destroyable/index.ts","lineNumber":295,"sourceCode":"if (DEBUG) {\n  let isTesting = false;\n\n  enableDestroyableTracking = () => {\n    if (isTesting) {\n      // Reset destroyable meta just in case, before throwing the error\n      DESTROYABLE_META = new WeakMap();\n      throw new Error(\n        'Attempted to start destroyable testing, but you did not end the previous destroyable test. Did you forget to call `assertDestroyablesDestroyed()`'\n      );\n    }\n\n    isTesting = true;\n    DESTROYABLE_META = new Map();\n  };\n\n  assertDestroyablesDestroyed = () => {\n    if (!isTesting) {\n      throw new Error(\n        'Attempted to assert destroyables destroyed, but you did not start a destroyable test. Did you forget to call `enableDestroyableTracking()`'\n      );\n    }\n\n    isTesting = false;\n\n    let map = DESTROYABLE_META as Map<Destroyable, DestroyableMeta<Destroyable>>;\n    DESTROYABLE_META = new WeakMap();\n\n    let undestroyed: object[] = [];\n\n    map.forEach((meta) => {\n      if (meta.state !== DESTROYED_STATE) {\n        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- @fixme\n        undestroyed.push(meta.source!);\n      }\n    });\n","sourceCodeStart":277,"sourceCodeEnd":313,"githubUrl":"https://github.com/emberjs/ember.js/blob/26f97246a8bf2e28edf26ac3093da2e86c04ffc5/packages/@glimmer/destroyable/index.ts#L277-L313","documentation":"`assertDestroyablesDestroyed()` verifies that all destroyables created during a tracking session were destroyed, but only works when tracking was started via `enableDestroyableTracking()`. If the `isTesting` flag is false when it is called, the library throws because there is nothing to assert against. This guards against asserting in production or outside a tracking session.","triggerScenarios":"Calling `assertDestroyablesDestroyed()` before ever calling `enableDestroyableTracking()`, or after a previous `assertDestroyablesDestroyed()` already reset `isTesting` to false (double assertion).","commonSituations":"afterEach hooks that call the assertion unconditionally even for tests that never enabled tracking; assertion order bugs where teardown runs before setup.","solutions":["Call `enableDestroyableTracking()` in beforeEach before asserting in afterEach","Ensure `assertDestroyablesDestroyed()` is only called once per tracking session","Guard the afterEach with a flag or check that tracking was actually started in that test","Initialize tracking in a shared test helper so setup/teardown order is guaranteed"],"exampleFix":"// before\nafterEach(() => { assertDestroyablesDestroyed(); });\n// after\nbeforeEach(() => { enableDestroyableTracking(); });\nafterEach(() => { assertDestroyablesDestroyed(); });","handlingStrategy":"validation","validationCode":"let trackingStarted = false;\nafterEach(function () {\n  if (trackingStarted) assertDestroyablesDestroyed();\n  trackingStarted = false;\n});","typeGuard":"const canAssertDestroyed = () => trackingStarted === true;","tryCatchPattern":"try { assertDestroyablesDestroyed(); } catch (e) { if (/did not start a destroyable test/.test(e.message)) { enableDestroyableTracking(); assertDestroyablesDestroyed(); } else throw e; }","preventionTips":["Call enableDestroyableTracking() in beforeEach whenever the assertion runs in afterEach","Track session state in your test helper to make teardown conditional","Never assert in production code paths where tracking is off"],"tags":["testing","destroyables","test-lifecycle"],"backgroundTag":"destroyable-tracking-not-started","analyzedSha":"26f97246a8bf2e28edf26ac3093da2e86c04ffc5","analyzedAt":"2026-09-01T05:01:28.182Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}