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
- Verify the file path/URL points to a real .exr (check `file scene.exr` says 'OpenEXR image data')
- Check the HTTP response was 200 and the server did not return an HTML error page
- Confirm the ArrayBuffer passed to the loader is the complete file, not a slice or a re-encoded texture
- 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
- Check HTTP status codes before treating a response as an asset
- Run `file asset.exr` in CI to catch mislabeled textures
- Validate the 0x76 0x2f 0x31 0x01 magic bytes before loading
- Avoid renaming files of a different format to .exr
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.