{"record":{"id":"9755272394183b5f","repo":"BabylonJS/Babylon.js","slug":"command-descriptor-id-is-already-registered","errorCode":null,"errorMessage":"Command '${descriptor.id}' is already registered.","messagePattern":"Command '(.+?)' is already registered\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/sharedUiComponents/src/modularTool/services/cli/bridgeService.ts","lineNumber":204,"sourceCode":"                            sendToBridge({\r\n                                type: \"commandResponse\",\r\n                                requestId: message.requestId,\r\n                                error: String(error),\r\n                            });\r\n                        }\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n\r\n            if (enabled) {\r\n                connect();\r\n            }\r\n\r\n            const registry: IBridgeCommandRegistry & ICliConnectionStatus & IDisposable = {\r\n                addCommand(descriptor: BridgeCommandDescriptor): IDisposable {\r\n                    if (commands.has(descriptor.id)) {\r\n                        throw new Error(`Command '${descriptor.id}' is already registered.`);\r\n                    }\r\n                    commands.set(descriptor.id, descriptor);\r\n                    return {\r\n                        dispose: () => {\r\n                            commands.delete(descriptor.id);\r\n                        },\r\n                    };\r\n                },\r\n                get isEnabled() {\r\n                    return enabled;\r\n                },\r\n                set isEnabled(value: boolean) {\r\n                    if (enabled !== value) {\r\n                        enabled = value;\r\n                        if (enabled) {\r\n                            connect();\r\n                        } else {\r\n                            disconnect();\r","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/sharedUiComponents/src/modularTool/services/cli/bridgeService.ts#L186-L222","documentation":"BridgeService's registry addCommand enforces unique command IDs: if commands.has(descriptor.id) the registration throws. Command IDs are primary keys for CLI dispatch, so duplicates would make routing ambiguous.","triggerScenarios":"Calling addCommand twice with descriptors sharing the same id; re-registering after reconnect without first disposing the previous registration handle; two modules registering a command with the same id string.","commonSituations":"Plugin hot-reload re-running registration code against a persistent registry; naming collisions between built-in and extension commands; forgetting to call dispose() on the IDisposable returned by addCommand before re-registering.","solutions":["Dispose the IDisposable returned by the first addCommand before registering again.","Check commands.has(id) (or wrap registration) before calling addCommand.","Namespace command ids per extension (e.g. 'myext.command') to avoid collisions.","On reconnect/hot-reload, rebuild or clear the registration set instead of re-adding."],"exampleFix":"// before\nbridge.addCommand({ id: \"build\", ... });\nbridge.addCommand({ id: \"build\", ... }); // throws\n// after\nconst reg = bridge.addCommand({ id: \"build\", ... });\n// on re-registration:\nreg.dispose();\nbridge.addCommand({ id: \"build\", ... });","handlingStrategy":"validation","validationCode":"function addCommandOnce(registry, descriptor) {\n  if (registeredIds.has(descriptor.id)) return; // skip duplicate\n  const handle = registry.addCommand(descriptor);\n  registeredIds.add(descriptor.id);\n  return {\n    dispose: () => {\n      registeredIds.delete(descriptor.id);\n      handle.dispose();\n    },\n  };\n}","typeGuard":null,"tryCatchPattern":"// try {\n//   return registry.addCommand(descriptor);\n// } catch (e) {\n//   if (String(e.message).includes(\"is already registered\")) return existingHandle; // idempotent\n//   throw e;\n// }","preventionTips":["Always dispose the handle from the previous addCommand before re-registering.","Namespace command ids per extension to avoid collisions.","On hot-reload/reconnect, reset the registration set."],"tags":["cli","duplicate-registration","command-registry"],"backgroundTag":"duplicate-command-id","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}