BabylonJS/Babylon.js · error · Error

Service '${service.friendlyName}' has dependents: ${Array.fr

Error message

Service '${service.friendlyName}' has dependents: ${Array.from(serviceDependents)
                    .map((dependent) => dependent.friendlyName)
                    .join(", ")}

What it means

_removeService refuses to remove a service while other services still depend on it: _serviceDependents.get(service) is non-empty. dispose() removes instances in reverse instantiation order, so this error indicates dependency bookkeeping is out of order or a dependent was never released.

Source

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

                dependentDefinitions.delete(consumer);
                if (dependentDefinitions.size === 0) {
                    this._serviceDependents.delete(definition);
                }
            }
            return;
        }

        this._parent?._removeDependentFromChain(contract, consumer);
    }

    private _removeService(service: WeaklyTypedServiceDefinition) {
        if (this._isDisposed) {
            throw new Error(`'${this._friendlyName}' container is disposed.`);
        }

        const serviceDependents = this._serviceDependents.get(service);
        if (serviceDependents && serviceDependents.size > 0) {
            throw new Error(
                `Service '${service.friendlyName}' has dependents: ${Array.from(serviceDependents)
                    .map((dependent) => dependent.friendlyName)
                    .join(", ")}`
            );
        }

        // NOTE: The service instance could be undefined, as the service factory for a service that does not produce any contracts is not required to return an actual service instance.
        const serviceInstance = this._serviceInstances.get(service);
        this._serviceInstances.delete(service);
        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);

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Release dependents first (let their cleanup run) before removing/disposing the producer.
  2. Ensure all consumers call the container's dependent-removal API in their dispose.
  3. Await all async module startup/teardown before disposing the container.
  4. Inspect the error's dependent list to find which consumers still hold references.

Example fix

// before
consumer.dispose(); // never unregisters as dependent
container.dispose(); // throws: producer has dependents
// after
consumer.dispose(); // internally calls container.removeDependent(producerContract, consumerDef)
container.dispose();
Defensive patterns

Strategy: validation

Validate before calling

// Release dependents before removing a producer
function safeRemoveProducer(container, producerContract, consumerDef) {
  // consumer must have unregistered itself first
  consumerDef.dispose?.(); // triggers removeDependent internally
  // then removal/dispose of the producer is safe
}

Try / catch

// try {
//   container.dispose();
// } catch (e) {
//   if (String(e.message).startsWith("Service '") && e.message.includes("has dependents:")) {
//     console.error("Release these consumers first:", e.message);
//   }
//   throw e;
// }

Prevention

When it happens

Trigger: Disposing the container while a dependent service was registered via dependencies() but not unregistered; manually removing a producer service that still has dependents; dependents added after the reverse-order teardown snapshot was taken.

Common situations: Custom removal of a shared/logger-like service consumed by many modules; dispose racing with a module still resolving dependencies (async startup not awaited); leaking dependent registrations because removeDependent was never called on consumer teardown.

Related errors


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