BabylonJS/Babylon.js · error · Error

Incorrect OpenEXR format

Error message

Incorrect OpenEXR format

What it means

GetExrHeader reads the first 4 bytes of the DataView and compares them to EXR_MAGIC (0x76, 0x2f, 0x31, 0x01 — the OpenEXR magic number 0x01312f76 little-endian). If they do not match, the input is not an OpenEXR file at all, so parsing stops immediately.

Source

Thrown at packages/dev/core/src/Materials/Textures/Loaders/EXR/exrLoader.header.ts:87

// // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// //
// ///////////////////////////////////////////////////////////////////////////

// // End of OpenEXR license -------------------------------------------------

const EXR_MAGIC = 20000630;

/**
 * Gets the EXR header
 * @param dataView defines the data view to read from
 * @param offset defines the offset to start reading from
 * @returns the header
 */
export function GetExrHeader(dataView: DataView, offset: DataCursor): IEXRHeader {
    if (dataView.getUint32(0, true) != EXR_MAGIC) {
        throw new Error("Incorrect OpenEXR format");
    }

    const version = dataView.getUint8(4);

    const specData = dataView.getUint8(5); // fullMask
    const spec = {
        singleTile: !!(specData & 2),
        longName: !!(specData & 4),
        deepFormat: !!(specData & 8),
        multiPart: !!(specData & 16),
    };

    offset.value = 8;

    const headerData: any = {};

    let keepReading = true;

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Verify the file path/URL points to a real .exr (check `file scene.exr` says 'OpenEXR image data')
  2. Check the HTTP response was 200 and the server did not return an HTML error page
  3. Confirm the ArrayBuffer passed to the loader is the complete file, not a slice or a re-encoded texture
  4. Re-export the asset as OpenEXR from the DCC tool

Example fix

// before: blindly loading whatever the URL returns
const res = await fetch(url);
loader.load(await res.blob());
// after: guard status and magic bytes
const res = await fetch(url);
if (!res.ok) throw new Error("fetch failed: " + res.status);
const buf = new Uint8Array(await res.arrayBuffer());
if (!(buf[0] === 0x76 && buf[1] === 0x2f && buf[2] === 0x31 && buf[3] === 0x01)) throw new Error("not an EXR file");
Defensive patterns

Strategy: validation

Validate before calling

async function fetchExr(url: string): Promise<ArrayBuffer> {
  const res = await fetch(url);
  if (!res.ok) throw new Error("HTTP " + res.status + " for EXR");
  const buf = await res.arrayBuffer();
  if (buf.byteLength < 8 || new DataView(buf).getUint32(0, true) !== 0x01312f76) throw new Error("not an OpenEXR file: " + url);
  return buf;
}

Type guard

function isOpenExrBuffer(buf: ArrayBuffer): boolean {
  return buf.byteLength >= 4 && new DataView(buf).getUint32(0, true) === 0x01312f76;
}

Try / catch

try {
  await loader.loadAsync(file);
} catch (e) {
  if (/Incorrect OpenEXR format/.test(String(e))) {
    console.error("File at url is not EXR — check path, HTTP status and file type");
    return loadPlaceholderTexture();
  }
  throw e;
}

Prevention

When it happens

Trigger: Raised in GetExrHeader (called by header) whenever dataView.getUint32(0, true) !== EXR_MAGIC: passing a PNG/JPG/HDR/EXR-variant renamed to .exr, an HTML error page saved as .exr, an empty/zero-length buffer, or a byte-swapped/big-endian dump.

Common situations: 404 responses saved as texture files, wrong file chosen in an asset pipeline, pipeline step writing a different format with an .exr extension, or loading a .tx/.dpx mislabeled as EXR.

Related errors


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