angular/components · error
Harness is attempting to use a fixture that has already been
Error message
Harness is attempting to use a fixture that has already been destroyed.
What it means
TestbedHarnessEnvironment keeps a reference to the ComponentFixture and stabilizes it before harness operations (auto change detection). Once the fixture is destroyed (e.g. afterEach teardown or fixture.destroy()), any harness use that triggers forceStabilize throws this error. It prevents interacting with a dead fixture's DOM.
Source
Thrown at src/cdk/testing/testbed/testbed-harness-environment.ts:171
static async harnessForFixture<T extends ComponentHarness>(
fixture: ComponentFixture<unknown>,
harnessType: ComponentHarnessConstructor<T>,
options?: TestbedHarnessEnvironmentOptions,
): Promise<T> {
const environment = new TestbedHarnessEnvironment(fixture.nativeElement, fixture, options);
await environment.forceStabilize();
return environment.createComponentHarness(harnessType, fixture.nativeElement);
}
/**
* Flushes change detection and async tasks captured in the Angular zone.
* In most cases it should not be necessary to call this manually. However, there may be some edge
* cases where it is needed to fully flush animation events.
*/
async forceStabilize(): Promise<void> {
if (!disableAutoChangeDetection) {
if (this._destroyed) {
throw Error('Harness is attempting to use a fixture that has already been destroyed.');
}
await detectChanges(this._fixture);
}
}
/**
* Waits for all scheduled or running async tasks to complete. This allows harness
* authors to wait for async tasks outside of the Angular zone.
*
* This only works when Zone.js is present _and_ patches are applied to the test framework
* by `zone.js/testing` (Jasmine and Jest only) or another script.
*/
async waitForTasksOutsideAngular(): Promise<void> {
// If we run in the fake async zone, we run "flush" to run any scheduled tasks. This
// ensures that the harnesses behave inside of the FakeAsyncTestZone similar to the
// "AsyncTestZone" and the root zone (i.e. neither fakeAsync or async). Note that we
// cannot just rely on the task state observable to become stable because the state willView on GitHub (pinned to 0411926e7d)
Solutions
- Recreate the fixture and harness inside each test (beforeEach) instead of reusing after destroy
- Ensure all harness interactions finish before fixture.destroy() is called (await them in the test body)
- Do not call fixture.destroy() manually mid-test while harnesses are still in use
- Check for async operations that outlive the test (unawaited promises, timers) that touch the fixture after teardown
Example fix
// before
let harness: ButtonHarness;
beforeEach(async () => { harness = await loader.getHarness(ButtonHarness); });
// after fixture destroyed in afterEach, using harness in next test throws
// after
it('...', async () => {
const harness = await loader.getHarness(ButtonHarness); // fresh per test
await harness.click();
}); Defensive patterns
Strategy: validation
Validate before calling
// before using a harness
if (fixture.isDestroyed ?? false) {
throw new Error('Fixture already destroyed; recreate fixture and harness');
}
// Track destruction explicitly:
let destroyed = false;
afterEach(() => { destroyed = true; fixture.destroy(); }); Type guard
function canUseFixture(f: ComponentFixture<unknown>): boolean {
return !f.isDestroyed;
} Try / catch
try {
await harness.getText();
} catch (e) {
if ((e as Error).message.includes('already been destroyed')) {
// recreate fixture + harness and retry once
fixture = TestBed.createComponent(MyComp);
loader = TestbedHarnessEnvironment.loader(fixture);
harness = await loader.getHarness(MyHarness);
} else { throw e; }
} Prevention
- Create fixture and harness inside each it(), not in outer scope
- Never call harness methods after afterEach teardown
- Await all harness interactions before fixture.destroy()
- Avoid storing harnesses in module-level variables
When it happens
Trigger: Calling any harness method (click, getText, setInputValue, etc.) or forceStabilize after fixture.destroy(); using harnesses created via harnessForFixture/getAllRawElements after the TestBed teardown; capturing a harness in a variable and using it in a later test.
Common situations: Storing harnesses at describe() scope and reusing across it() blocks; awaiting long-running assertions after Angular's autoDestroy on test end; creating harnesses in beforeEach but consuming after an explicit destroy; TestBed auto-detecting changes then autoDestroy running before a pending promise resolves.
Related errors
- Index must not be negative
- No harness was located at index ${offset}
- CDK Component harness query must contain at least one elemen
- Failed to find element matching one of the following queries
- No keys have been specified.
AI-assisted analysis of angular/components@0411926e7d (2026-08-31).
Data as JSON: /api/errors/d67c3b2f500c991c.
Report an issue: GitHub.