{"record":{"id":"3103419394a8fc33","repo":"emberjs/ember.js","slug":"attempted-to-start-destroyable-testing-but-you-di","errorCode":null,"errorMessage":"Attempted to start destroyable testing, but you did not end the previous destroyable test. Did you forget to call `assertDestroyablesDestroyed()`","messagePattern":"Attempted to start destroyable testing, but you did not end the previous destroyable test\\. Did you forget to call `assertDestroyablesDestroyed\\(\\)`","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@glimmer/destroyable/index.ts","lineNumber":284,"sourceCode":"export function isDestroyed(destroyable: Destroyable) {\n  let meta = peekDestroyableMeta(destroyable);\n\n  return meta === undefined ? false : meta.state >= DESTROYED_STATE;\n}\n\n////////////\n\nexport let enableDestroyableTracking: undefined | (() => void);\nexport let assertDestroyablesDestroyed: undefined | (() => void);\n\nif (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>>;","sourceCodeStart":266,"sourceCodeEnd":302,"githubUrl":"https://github.com/emberjs/ember.js/blob/26f97246a8bf2e28edf26ac3093da2e86c04ffc5/packages/@glimmer/destroyable/index.ts#L266-L302","documentation":"This error comes from @glimmer/destroyable's test tracking mode. `enableDestroyableTracking()` flips an `isTesting` flag; if it is called while a previous tracking session is still active, the library throws rather than silently discarding the previous session's destroyable meta. It exists to enforce that each tracking session is paired with `assertDestroyablesDestroyed()`.","triggerScenarios":"Calling `enableDestroyableTracking()` twice without an intervening `assertDestroyablesDestroyed()` call (e.g. in a shared beforeEach, nested test setup, or a test helper that forgets the assertion step).","commonSituations":"Ember/Glimmer test suites where destroyable tracking is enabled per-test but the assertion helper was dropped from an afterEach hook, or a test throws before `assertDestroyablesDestroyed()` runs leaving `isTesting` true for subsequent tests.","solutions":["Add `assertDestroyablesDestroyed()` in an afterEach hook (or after each test) to properly end the tracking session before the next `enableDestroyableTracking()` call","Audit test setup for duplicate `enableDestroyableTracking()` calls (e.g. double-registered beforeEach hooks)","Wrap tracking start/end in a helper that guarantees pairing even on test failure (try/finally)","Reset test state between suites so the module-level `isTesting` flag starts fresh"],"exampleFix":"// before\nbeforeEach(() => { enableDestroyableTracking(); });\n// after\nbeforeEach(() => { enableDestroyableTracking(); });\nafterEach(() => { assertDestroyablesDestroyed(); });","handlingStrategy":"validation","validationCode":"let trackingActive = false;\nfunction startTracking() {\n  if (trackingActive) { assertDestroyablesDestroyed(); }\n  enableDestroyableTracking();\n  trackingActive = true;\n}\nfunction endTracking() {\n  assertDestroyablesDestroyed();\n  trackingActive = false;\n}","typeGuard":"const isTrackingActive = () => destroyablesTestingFlag === true; // via a wrapper module that owns the state","tryCatchPattern":"try { enableDestroyableTracking(); runTest(); } catch (e) { if (!/did not end the previous/.test(e.message)) throw e; assertDestroyablesDestroyed(); enableDestroyableTracking(); runTest(); }","preventionTips":["Always pair enableDestroyableTracking() with assertDestroyablesDestroyed() in setup/teardown hooks","Use a single shared test helper for destroyable tracking across the suite","Avoid enabling tracking in nested or overlapping scopes"],"tags":["testing","destroyables","test-lifecycle"],"backgroundTag":"destroyable-tracking-not-ended","analyzedSha":"26f97246a8bf2e28edf26ac3093da2e86c04ffc5","analyzedAt":"2026-09-01T05:01:28.182Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}