BabylonJS/Babylon.js · error · Error
Command '${descriptor.id}' is already registered.
Error message
Command '${descriptor.id}' is already registered. What it means
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.
Source
Thrown at packages/dev/sharedUiComponents/src/modularTool/services/cli/bridgeService.ts:204
sendToBridge({
type: "commandResponse",
requestId: message.requestId,
error: String(error),
});
}
break;
}
}
}
if (enabled) {
connect();
}
const registry: IBridgeCommandRegistry & ICliConnectionStatus & IDisposable = {
addCommand(descriptor: BridgeCommandDescriptor): IDisposable {
if (commands.has(descriptor.id)) {
throw new Error(`Command '${descriptor.id}' is already registered.`);
}
commands.set(descriptor.id, descriptor);
return {
dispose: () => {
commands.delete(descriptor.id);
},
};
},
get isEnabled() {
return enabled;
},
set isEnabled(value: boolean) {
if (enabled !== value) {
enabled = value;
if (enabled) {
connect();
} else {
disconnect();
View on GitHub (pinned to 0592b347b8)
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.
Example fix
// before
bridge.addCommand({ id: "build", ... });
bridge.addCommand({ id: "build", ... }); // throws
// after
const reg = bridge.addCommand({ id: "build", ... });
// on re-registration:
reg.dispose();
bridge.addCommand({ id: "build", ... }); Defensive patterns
Strategy: validation
Validate before calling
function addCommandOnce(registry, descriptor) {
if (registeredIds.has(descriptor.id)) return; // skip duplicate
const handle = registry.addCommand(descriptor);
registeredIds.add(descriptor.id);
return {
dispose: () => {
registeredIds.delete(descriptor.id);
handle.dispose();
},
};
} Try / catch
// try {
// return registry.addCommand(descriptor);
// } catch (e) {
// if (String(e.message).includes("is already registered")) return existingHandle; // idempotent
// throw e;
// } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Unable to connect to the Inspector bridge on port ${port} af
- Session id must be a number.
- Session ${parsed} does not exist. No active sessions.
- Session ${parsed} does not exist. Active sessions: ${list}
- A session id is required. Use --session to list active sessi
AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30).
Data as JSON: /api/errors/9755272394183b5f.
Report an issue: GitHub.