BabylonJS/Babylon.js · error · Error

'${this._friendlyName}' container cannot be disposed because

Error message

'${this._friendlyName}' container cannot be disposed because it has ${this._children.size} active child container(s).

What it means

dispose() refuses to dispose a container that still has live child containers in _children. Child containers may resolve services through this parent, so disposing the parent first would orphan them; children must be disposed before their parent.

Source

Thrown at packages/dev/sharedUiComponents/src/modularTool/modularity/serviceContainer.ts:207

        serviceInstance?.dispose?.();

        service.produces?.forEach((contract) => {
            this._serviceDefinitions.delete(contract);
        });

        // Remove this service as a dependent from each of its consumed dependencies (local or in parent chain).
        service.consumes?.forEach((contract) => {
            this._removeDependentFromChain(contract, service);
        });
    }

    /**
     * Disposes the service container and all contained services.
     * Throws if this container is still a parent of any live child containers.
     */
    public dispose() {
        if (this._children.size > 0) {
            throw new Error(`'${this._friendlyName}' container cannot be disposed because it has ${this._children.size} active child container(s).`);
        }

        Array.from(this._serviceInstances.keys()).reverse().forEach(this._removeService.bind(this));
        this._serviceInstances.clear();
        this._serviceDependents.clear();
        this._serviceDefinitions.clear();
        this._parent?._children.delete(this);
        this._isDisposed = true;
    }
}

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Dispose all child containers first, then the parent (depth-first teardown).
  2. Keep a registry of created children in the owner and dispose them in cleanup.
  3. Make parent disposal automatically dispose children only if the library API permits; otherwise fix ordering at call sites.
  4. In tests, use afterEach to dispose any containers created during the test.

Example fix

// before
parent.dispose(); // throws: has 2 active child containers
// after
children.forEach((c) => c.dispose());
parent.dispose();
Defensive patterns

Strategy: validation

Validate before calling

// const children = getActiveChildren(parent); // your own registry
// if (children.length) children.forEach((c) => c.dispose());
// parent.dispose();

Try / catch

// try {
//   parent.dispose();
// } catch (e) {
//   if (e.message.includes("active child container")) {
//     throw new Error("Dispose child containers before the parent", { cause: e });
//   }
//   throw e;
// }

Prevention

When it happens

Trigger: Calling parentContainer.dispose() while createChild/derived child containers are still alive; a child created but its dispose never called in cleanup; children tracked outside the container so teardown order is wrong.

Common situations: Tool shutdown disposing the root container while plugin scopes (children) remain open; leaked child containers from aborted initialization; tests forgetting per-test child container cleanup.

Related errors


AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30). Data as JSON: /api/errors/fc52c790efd5026b. Report an issue: GitHub.