{"record":{"id":"7214dad69fb63cf4","repo":"BabylonJS/Babylon.js","slug":"service-service-friendlyname-has-dependents","errorCode":null,"errorMessage":"Service '${service.friendlyName}' has dependents: ${Array.from(serviceDependents)\n                    .map((dependent) => dependent.friendlyName)\n                    .join(\", \")}","messagePattern":"Service '(.+?)' has dependents: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/sharedUiComponents/src/modularTool/modularity/serviceContainer.ts","lineNumber":179,"sourceCode":"                dependentDefinitions.delete(consumer);\r\n                if (dependentDefinitions.size === 0) {\r\n                    this._serviceDependents.delete(definition);\r\n                }\r\n            }\r\n            return;\r\n        }\r\n\r\n        this._parent?._removeDependentFromChain(contract, consumer);\r\n    }\r\n\r\n    private _removeService(service: WeaklyTypedServiceDefinition) {\r\n        if (this._isDisposed) {\r\n            throw new Error(`'${this._friendlyName}' container is disposed.`);\r\n        }\r\n\r\n        const serviceDependents = this._serviceDependents.get(service);\r\n        if (serviceDependents && serviceDependents.size > 0) {\r\n            throw new Error(\r\n                `Service '${service.friendlyName}' has dependents: ${Array.from(serviceDependents)\r\n                    .map((dependent) => dependent.friendlyName)\r\n                    .join(\", \")}`\r\n            );\r\n        }\r\n\r\n        // 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.\r\n        const serviceInstance = this._serviceInstances.get(service);\r\n        this._serviceInstances.delete(service);\r\n        serviceInstance?.dispose?.();\r\n\r\n        service.produces?.forEach((contract) => {\r\n            this._serviceDefinitions.delete(contract);\r\n        });\r\n\r\n        // Remove this service as a dependent from each of its consumed dependencies (local or in parent chain).\r\n        service.consumes?.forEach((contract) => {\r\n            this._removeDependentFromChain(contract, service);\r","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/sharedUiComponents/src/modularTool/modularity/serviceContainer.ts#L161-L197","documentation":"_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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Release dependents first (let their cleanup run) before removing/disposing the producer.","Ensure all consumers call the container's dependent-removal API in their dispose.","Await all async module startup/teardown before disposing the container.","Inspect the error's dependent list to find which consumers still hold references."],"exampleFix":"// before\nconsumer.dispose(); // never unregisters as dependent\ncontainer.dispose(); // throws: producer has dependents\n// after\nconsumer.dispose(); // internally calls container.removeDependent(producerContract, consumerDef)\ncontainer.dispose();","handlingStrategy":"validation","validationCode":"// Release dependents before removing a producer\nfunction safeRemoveProducer(container, producerContract, consumerDef) {\n  // consumer must have unregistered itself first\n  consumerDef.dispose?.(); // triggers removeDependent internally\n  // then removal/dispose of the producer is safe\n}","typeGuard":null,"tryCatchPattern":"// try {\n//   container.dispose();\n// } catch (e) {\n//   if (String(e.message).startsWith(\"Service '\") && e.message.includes(\"has dependents:\")) {\n//     console.error(\"Release these consumers first:\", e.message);\n//   }\n//   throw e;\n// }","preventionTips":["Consumers must call removeDependent (or equivalent) in their own dispose.","Await all async startup/teardown before disposing the container.","Remove services in reverse dependency order; prefer container.dispose() over manual removal."],"tags":["dependency-injection","lifecycle","disposal-order"],"backgroundTag":"service-has-dependents","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}