BabylonJS/Babylon.js · critical

Plugin version is incorrect. Expected version 2.

Error message

Plugin version is incorrect. Expected version 2.

What it means

PhysicsBody is the v2 physics API. After finding the scene's engine it checks physicsEngine.getPluginVersion() == 2; if the engine was created with a v1 plugin (e.g. legacy Cannon/Oimo plugins), the v2 body API is incompatible and the constructor throws to prevent undefined behavior.

Source

Thrown at packages/dev/core/src/Physics/v2/physicsBody.ts:112

     *  - PhysicsMotionType.ANIMATED - They behave like dynamic bodies, but they won't be affected by other bodies, but still push other bodies out of the way.
     * @param startsAsleep - Whether the physics body should start in a sleeping state (not a guarantee). Defaults to false.
     * @param scene - The scene containing the physics engine.
     *
     * This code is useful for creating a physics body for a given Transform Node in a scene.
     * It checks the version of the physics engine and the physics plugin, and initializes the body accordingly.
     * It also sets the node's rotation quaternion if it is not already set. Finally, it adds the body to the physics engine.
     */
    constructor(transformNode: TransformNode, motionType: PhysicsMotionType, startsAsleep: boolean, scene: Scene) {
        if (!scene) {
            return;
        }
        const physicsEngine = scene.getPhysicsEngine() as PhysicsEngine;
        if (!physicsEngine) {
            throw new Error("No Physics Engine available.");
        }
        this._physicsEngine = physicsEngine;
        if (physicsEngine.getPluginVersion() != 2) {
            throw new Error("Plugin version is incorrect. Expected version 2.");
        }
        const physicsPlugin = physicsEngine.getPhysicsPlugin();
        if (!physicsPlugin) {
            throw new Error("No Physics Plugin available.");
        }

        this._physicsPlugin = physicsPlugin;
        if (!transformNode.rotationQuaternion) {
            transformNode.rotationQuaternion = Quaternion.FromEulerAngles(transformNode.rotation.x, transformNode.rotation.y, transformNode.rotation.z);
        }

        this.startAsleep = startsAsleep;

        // only dynamic and animated body needs sync from physics to transformNode
        this.disableSync = motionType == PhysicsMotionType.STATIC;

        // instances?
        const m = transformNode as Mesh;

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Enable physics with a v2 plugin: const havok = await HavokPlugin(); scene.enablePhysics(grav, havok); then use PhysicsBody/PhysicsAggregate instead of PhysicsImpostor.
  2. Verify the plugin's getPluginVersion() === 2 before constructing v2 physics objects.
  3. If you must stay on a v1 plugin, use the v1 API (PhysicsImpostor) rather than PhysicsBody.

Example fix

// before
scene.enablePhysics(grav, new CannonJSPlugin());
const body = new PhysicsBody(mesh, PhysicsMotionType.DYNAMIC, false, scene);
// after
const havok = await HavokPlugin();
scene.enablePhysics(grav, havok); // version 2 plugin
const body = new PhysicsBody(mesh, PhysicsMotionType.DYNAMIC, false, scene);
Defensive patterns

Strategy: validation

Validate before calling

const engine = scene.getPhysicsEngine() as PhysicsEngine | null;
if (!engine || engine.getPluginVersion() !== 2) {
  throw new Error("PhysicsBody requires a v2 physics plugin (e.g. HavokPlugin)");
}

Prevention

When it happens

Trigger: new PhysicsBody(...) when the scene engine was enabled with a v1 plugin such as CannonJSPlugin/OimoJSPlugin/AmmoJSPlugin, so getPluginVersion() returns 1 and the check at physicsBody.ts:112 fails.

Common situations: Upgrading code that used the old v1 API (PhysicsImpostor era plugins) but keeping the legacy plugin; enabling physics with a legacy plugin by mistake; documentation mixing v1 and v2 examples.

Related errors


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