BabylonJS/Babylon.js · error

Invalid or empty skeleton provided

Error message

Invalid or empty skeleton provided

What it means

BVHExporter.Export validates its input before building the BVH motion text: the skeleton must exist and contain at least one bone. Otherwise there is no hierarchy to write and the export is aborted. The message also covers a non-null skeleton with zero bones.

Source

Thrown at packages/dev/serializers/src/BVH/bvhSerializer.ts:23

import { Vector3, Quaternion, Matrix } from "core/Maths/math.vector";
import { Tools } from "core/Misc/tools";
import { Epsilon } from "core/Maths/math.constants";
import { type Nullable } from "core/types";

interface IBVHBoneData {
    bone: Bone;
    children: IBVHBoneData[];
    hasPositionChannels: boolean;
    hasRotationChannels: boolean;
    positionKeys: IAnimationKey[];
    rotationKeys: IAnimationKey[];
}

export class BVHExporter {
    public static Export(skeleton: Skeleton, animationNames: string[] = [], frameRate?: number): string {
        // Validate skeleton
        if (!skeleton || skeleton.bones.length === 0) {
            throw new Error("Invalid or empty skeleton provided");
        }

        // If no animation names provided, use all available animations
        let animationsToExport = animationNames;
        if (!animationNames || animationNames.length === 0) {
            animationsToExport = skeleton.animations.map((anim) => anim.name);
        }

        // Calculate overall animation range from all specified animations
        let overallRange: Nullable<AnimationRange> = null;
        for (const animName of animationsToExport) {
            const range = skeleton.getAnimationRange(animName);
            if (range) {
                overallRange = overallRange ? new AnimationRange("animation-range", Math.min(overallRange.from, range.from), Math.max(overallRange.to, range.to)) : range;
            }
        }

        if (!overallRange) {

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Check skeleton && skeleton.bones.length > 0 before calling Export
  2. Ensure the skeleton was built (e.g. from a mesh or importer) and bones are loaded before exporting
  3. Verify the scene/skeleton reference is correct (not undefined from a failed scene.getSkeletonByName)

Example fix

// before
const bvh = BVHExporter.Export(scene.getSkeletonByName("rig")!); // may throw
// after
const skel = scene.getSkeletonByName("rig");
if (skel && skel.bones.length > 0) {
    const bvh = BVHExporter.Export(skel);
}
Defensive patterns

Strategy: validation

Validate before calling

if (!skeleton || skeleton.bones.length === 0) {
  throw new Error(`Cannot export BVH: skeleton '${name}' missing or has no bones`);
}

Type guard

function isExportableSkeleton(s: Skeleton | null | undefined): s is Skeleton {
  return !!s && Array.isArray(s.bones) && s.bones.length > 0;
}

Try / catch

try {
  const bvh = BVHExporter.Export(skeleton);
} catch (e) {
  if (String(e.message).includes("Invalid or empty skeleton")) {
    logger.warn("Skipping BVH export: skeleton not built yet", e);
  } else throw e;
}

Prevention

When it happens

Trigger: Passing null/undefined to BVHExporter.Export, or a Skeleton instance whose bones array is empty (skeleton created but bones never built, or joints not yet linked).

Common situations: Calling export before skeleton.buildFromMesh / before the skeleton is constructed from a mesh; a scene load that silently failed leaving an empty Skeleton; retrieving a skeleton by name from the scene with a typo and getting undefined.

Related errors


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