BabylonJS/Babylon.js · error · Error

Invalid FBX node end offset ${endOffset} at offset ${offset}

Error message

Invalid FBX node end offset ${endOffset} at offset ${offset}

What it means

Each binary FBX node record starts with an end-offset field. The offset-based bounds check in parseNode requires endOffset to be strictly greater than the node's own offset and within the parent's limit; values of 0 are the legal null sentinel (handled above), so any other out-of-range value means the record header is corrupt or the assumed header layout (32-bit vs 64-bit) is wrong.

Source

Thrown at packages/dev/loaders/src/FBX/parsers/fbxBinaryParser.ts:75

        ensureRange(bytes, offset, 25, limit, "FBX node header");
        endOffset = readUint64AsNumber(view, offset);
        numProperties = readUint64AsNumber(view, offset + 8);
        propertyListLen = readUint64AsNumber(view, offset + 16);
        headerSize = 25; // 8+8+8+1 (nameLen byte)
    } else {
        ensureRange(bytes, offset, 13, limit, "FBX node header");
        endOffset = view.getUint32(offset, true);
        numProperties = view.getUint32(offset + 4, true);
        propertyListLen = view.getUint32(offset + 8, true);
        headerSize = 13; // 4+4+4+1 (nameLen byte)
    }

    // Null sentinel: all header fields are zero
    if (endOffset === 0) {
        return null;
    }
    if (endOffset <= offset || endOffset > limit) {
        throw new Error(`Invalid FBX node end offset ${endOffset} at offset ${offset}`);
    }

    const nameLen = bytes[offset + headerSize - 1];
    ensureRange(bytes, offset + headerSize, nameLen, endOffset, "FBX node name");
    const name = decodeASCII(bytes, offset + headerSize, nameLen);

    let cursor = offset + headerSize + nameLen;
    const propertiesStart = cursor;
    const propertiesEnd = propertiesStart + propertyListLen;
    if (propertiesEnd > endOffset) {
        throw new Error(`Invalid FBX property list length for node '${name}' at offset ${offset}`);
    }

    // Parse properties
    const properties: FBXProperty[] = [];
    for (let i = 0; i < numProperties; i++) {
        const result = parseProperty(view, bytes, cursor, propertiesEnd);
        properties.push(result.property);

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Verify the FBX version read at byte 23 is correct for the file (≥7500 ⇒ 64-bit offsets); dump the first 32 bytes to inspect
  2. Re-export the FBX (try both binary FBX 2014/2016 and 2020) from the source tool
  3. Re-download the file — corruption in transit is the most common cause
  4. Compare against a known-good FBX with the same version to check header layout assumptions
Defensive patterns

Strategy: try-catch

Validate before calling

const v = new DataView(buffer).getUint32(23, true);
if (v < 6000 || v > 10000) throw new Error(`Implausible FBX version ${v}`); // also flags layout mismatch

Type guard

function hasPlausibleFbxVersion(buf) {
  if (buf.byteLength < 27) return false;
  const version = new DataView(buf).getUint32(23, true);
  return version >= 6000 && version <= 10000;
}

Try / catch

try {
  const doc = parseBinaryFBX(buffer);
} catch (e) {
  if (/Invalid FBX node end offset/.test(e.message)) {
    console.error("Node record out of bounds — file corrupt or 32/64-bit header mismatch; re-export FBX");
  } else throw e;
}

Prevention

When it happens

Trigger: Parsing node records (via `result`/`child` recursion) where the read endOffset is <= current offset or exceeds the parse limit — typically caused by a corrupted file, or by reading a v7.5+ (64-bit header) file with the 32-bit header layout when version detection failed.

Common situations: FBX files ≥7500 exported with unusual headers misread due to a wrong version at offset 23; bit-flipped/corrupted downloads; third-party exporters writing non-conformant node records.

Related errors


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