thatopen-errors-loading
Loading Errors: Diagnosis & Recovery
Overview
This skill covers every failure mode that occurs when loading IFC files or initializing the ThatOpen fragment pipeline. Each error pattern maps to a specific root cause and a concrete fix.
Use this skill when:
- An IFC file fails to load or parse
- WASM initialization throws errors
- The viewer shows nothing after loading
- Fragment worker errors appear in the console
- Elements are missing from the loaded model
Critical Warnings
- ALWAYS call
await ifcLoader.setup()beforeifcLoader.load()— skipping setup causes silent null reference failures. - ALWAYS call
fragmentsManager.init(workerURL)before any fragment operation — the worker is required for all data operations. - ALWAYS match the WASM file version to the installed
web-ifcnpm package version — mismatches causeRuntimeError: unreachable. - NEVER pass a
stringorFileobject toifcLoader.load()— it requiresUint8Array. - ALWAYS include a trailing slash in WASM paths —
"/wasm/"not"/wasm". - ALWAYS serve
.wasmfiles with MIME typeapplication/wasm— incorrect MIME types causeCompileError. - ALWAYS configure COOP/COEP headers for multi-threaded WASM —
SharedArrayBufferrequires cross-origin isolation. - NEVER assume all IFC entity types load by default — check
excludedCategoriesif elements are missing.
Error Message to Fix Mapping
| Error Message / Symptom | Root Cause | Fix | Section |
|---|---|---|---|
RuntimeError: unreachable |
WASM version mismatch | Match WASM files to npm version | E-01 |
CompileError: WebAssembly.instantiate() |
Corrupt/wrong WASM file or MIME type | Serve .wasm as application/wasm |
E-02 |
404 Not Found on web-ifc.wasm |
Wrong WASM path | Fix path, add trailing slash | E-03 |
Cannot read properties of undefined on load |
setup() not called |
ALWAYS call await ifcLoader.setup() first |
E-04 |
FragmentsManager not initialized |
Worker not initialized | Call fragmentsManager.init(workerURL) |
E-05 |
| Model loads but nothing renders | Missing components.init() or scene add |
Call components.init(), add model.object to scene |
E-06 |
| Elements missing from model | Default excludedCategories |
Add missing classes via onIfcImporterInitialized |
E-07 |
TypeError: data is not Uint8Array |
Wrong data type passed to load() |
Convert to new Uint8Array(buffer) |
E-08 |
| Geometry at wrong position / z-fighting | Large world coordinates | Use COORDINATE_TO_ORIGIN: true |
E-09 |
SharedArrayBuffer is not defined |
Missing COOP/COEP headers | Configure server headers for cross-origin isolation | E-10 |
| Worker script 404 / CORS error | Wrong worker URL or CORS policy | Fix worker URL path, configure CORS headers | E-11 |
| Boolean operation hangs / infinite loop | Complex geometry timeout | Set BOOL_ABORT_THRESHOLD |
E-12 |
Invalid IFC file or empty model |
Corrupt file or wrong encoding | Validate IFC header, ensure binary fetch | E-13 |
| Tab crashes on large model | WASM memory exhaustion | Set MEMORY_LIMIT, use streaming |
E-14 |
E-01: WASM Version Mismatch
Error: RuntimeError: unreachable or CompileError during WASM instantiation.
Cause: The .wasm binary file version does not match the installed web-ifc npm package version. The WASM binary and JavaScript API are tightly coupled — a mismatch causes undefined behavior.
Diagnostic:
- Check installed version:
npm ls web-ifc - Check WASM path in code — does the version in the CDN URL match?
- If using local files, were they copied from the correct
node_modules/web-ifc/version?
Fix:
// Option A: Use autoSetWasm (recommended)
await ifcLoader.setup(); // autoSetWasm: true resolves correct version automatically
// Option B: Match CDN version to installed package
await ifcLoader.setup({
autoSetWasm: false,
wasm: {
path: "https://unpkg.com/web-ifc@0.0.77/", // MUST match npm ls web-ifc
absolute: true,
},
});
Rule: NEVER hardcode a web-ifc version without verifying it matches the installed npm package. ALWAYS prefer autoSetWasm: true unless you have a specific reason for manual configuration.
E-02: WASM MIME Type Error
Error: CompileError: WebAssembly.instantiate(): expected magic word or similar compilation failure.
Cause: The web server serves .wasm files with the wrong MIME type (e.g., application/octet-stream or text/html for a 404 page). Browsers require application/wasm.
Diagnostic:
- Open DevTools Network tab
- Find the
web-ifc.wasmrequest - Check the
Content-Typeresponse header
Fix (server configuration):
| Server | Configuration |
|---|---|
| Nginx | types { application/wasm wasm; } |
| Apache | AddType application/wasm .wasm |
| Express | express.static(dir, { setHeaders: (res, path) => { if (path.endsWith('.wasm')) res.type('application/wasm'); } }) |
| Vite | Handled automatically |
| Webpack | Use file-loader or copy-webpack-plugin with correct MIME |
Rule: ALWAYS verify the server serves .wasm files with Content-Type: application/wasm.
E-03: WASM Path Misconfiguration
Error: 404 Not Found on web-ifc.wasm or web-ifc-mt.wasm.
Cause: The WASM path does not resolve to the directory containing the WASM files. Common mistakes: missing trailing slash, wrong relative path, files not copied to public directory.
Diagnostic checklist:
- Does the path end with
/? - Does the directory actually contain
web-ifc.wasm? - Is
absolute: trueset when using a full URL? - For local paths: are the files in the build output / public directory?
Fix:
// WRONG: missing trailing slash
wasm: { path: "https://unpkg.com/web-ifc@0.0.77", absolute: true }
// WRONG: relative path with absolute: true
wasm: { path: "/static/wasm/", absolute: true }
// CORRECT: CDN with trailing slash
wasm: { path: "https://unpkg.com/web-ifc@0.0.77/", absolute: true }
// CORRECT: local path (relative to document base)
wasm: { path: "/static/wasm/", absolute: false }
Rule: ALWAYS include a trailing slash in WASM paths. The runtime appends web-ifc.wasm directly to this string.
E-04: setup() Not Called Before load()
Error: Cannot read properties of undefined, silent failure, or WASM not initialized.
Cause: IfcLoader implements the Configurable interface. WASM initialization happens inside setup(), not in the constructor or components.get().
Fix:
const ifcLoader = components.get(OBC.IfcLoader);
await ifcLoader.setup(); // ALWAYS await before load()
const model = await ifcLoader.load(data, true, "Building");
Rule: ALWAYS call await ifcLoader.setup() before calling load(). This is the single most common loading failure.
E-05: FragmentsManager Worker Not Initialized
Error: FragmentsManager not initialized, model fails to process, or worker-related errors in console.
Cause: The fragment system requires a Web Worker for processing IFC-to-Fragments conversion. Without init(), the worker is not available.
Fix:
const fragmentsManager = components.get(OBC.FragmentsManager);
fragmentsManager.init(workerURL); // ALWAYS call before any IFC loading
const ifcLoader = components.get(OBC.IfcLoader);
await ifcLoader.setup();
Diagnostic: If workerURL is wrong, you will see a 404 or CORS error. See E-11 for worker URL issues.
Rule: ALWAYS initialize FragmentsManager with a valid worker URL before any loading operations.
E-06: Silent Render Failure
Error: No error messages, but the viewer shows nothing (black screen or empty viewport).
Cause (check in order):
components.init()not called — the render loop never startsmodel.objectnot added to the scene- Camera not pointing at the model
- Container element has zero dimensions (0px height)
Fix:
// 1. Start render loop
components.init();
// 2. Add model to scene
const model = await ifcLoader.load(data, true, "Building");
world.scene.three.add(model.object);
// 3. Frame the camera on the model
world.camera.fit(world.scene.three.children);
// 4. Ensure container has dimensions
// CSS: #viewer { width: 100%; height: 100vh; }
Diagnostic checklist:
- Is
components.init()called? - Is
model.objectadded toworld.scene.three? - Does the container element have non-zero
offsetWidthandoffsetHeight? - Is the camera positioned to see the model?
Rule: ALWAYS call components.init() and ALWAYS add model.object to the scene after loading.
E-07: Missing IFC Elements
Error: Model loads successfully but certain element types (spaces, openings, furnishing) are absent.
Cause: The IfcImporter has a default classes.elements set that excludes some IFC categories for performance. Common exclusions: IFCSPACE, IFCOPENINGELEMENT, IFCFLOWSEGMENT, IFCFLOWFITTING.
Fix:
ifcLoader.onIfcImporterInitialized.add((importer) => {
// Add missing categories
importer.classes.elements.add(WEBIFC.IFCSPACE);
importer.classes.elements.add(WEBIFC.IFCOPENINGELEMENT);
importer.classes.elements.add(WEBIFC.IFCFLOWSEGMENT);
});
Diagnostic: Before loading, log available types after loading with ifcApi.GetAllTypesOfModel(modelID) to verify which IFC types exist in the file.
Rule: ALWAYS check the default element class set when elements are missing. NEVER assume all IFC entity types are imported by default.
E-08: Wrong Data Type for load()
Error: TypeError, Invalid IFC file, or empty model.
Cause: load() requires Uint8Array. Passing ArrayBuffer, string, Blob, or File directly causes failures.
Fix:
// From fetch
const buffer = await response.arrayBuffer();
const data = new Uint8Array(buffer);
// From File input
const data = new Uint8Array(await file.arrayBuffer());
// From base64
const binary = atob(base64String);
const data = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) data[i] = binary.charCodeAt(i);
Rule: ALWAYS convert to Uint8Array before passing to load().
E-09: Large Coordinate / Floating-Point Issues
Error: Model appears but geometry is distorted, flickering (z-fighting), or positioned far from origin causing camera issues.
Cause: IFC models often use real-world coordinates (e.g., UTM: x=500000, y=6000000). WebGL uses 32-bit floats — at these magnitudes, precision is ~1 meter, causing visible artifacts.
Fix:
await ifcLoader.setup();
ifcLoader.settings.webIfc.COORDINATE_TO_ORIGIN = true;
const model = await ifcLoader.load(data, true, "Building");
For multi-model coordination, use the coordination matrix instead:
// Load at origin, then apply coordination manually
const model = await ifcLoader.load(data, true, "Building");
// FragmentsManager handles coordination when coordinate=true
Rule: ALWAYS use COORDINATE_TO_ORIGIN: true for models with large world coordinates. For multi-model federation, use the coordinate parameter in load().
E-10: SharedArrayBuffer Not Available
Error: SharedArrayBuffer is not defined, multi-threaded WASM fails, or falls back to single-threaded mode silently.
Cause: SharedArrayBuffer requires cross-origin isolation via HTTP headers. Without these headers, browsers disable SharedArrayBuffer for security.
Required HTTP headers:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Fix per environment:
| Environment | Configuration |
|---|---|
| Vite | server: { headers: { 'Cross-Origin-Opener-Policy': 'same-origin', 'Cross-Origin-Embedder-Policy': 'require-corp' } } |
| Webpack devServer | Same headers in devServer.headers |
| Nginx | add_header Cross-Origin-Opener-Policy same-origin; add_header Cross-Origin-Embedder-Policy require-corp; |
| Vercel | vercel.json headers configuration |
Warning: Enabling these headers means all cross-origin resources (images, scripts, iframes) MUST have appropriate CORS headers or crossorigin attributes. This can break third-party integrations.
Rule: ALWAYS configure COOP/COEP headers for production deployments that need multi-threaded WASM. If you cannot set these headers, web-ifc falls back to single-threaded mode — functional but slower.
E-11: Worker Initialization Failures
Error: 404 on worker script, DOMException: Failed to construct 'Worker', or CORS errors loading worker.
Cause: The worker URL passed to fragmentsManager.init() does not resolve or is blocked by CORS policy.
Diagnostic:
- Open DevTools Network tab — is the worker script request returning 200?
- Is the worker URL correct relative to the document origin?
- For cross-origin workers, is the server setting
Access-Control-Allow-Origin?
Fix:
// Local worker file (most common)
fragmentsManager.init("/workers/fragment-worker.mjs");
// CDN worker (requires CORS)
fragmentsManager.init("https://cdn.example.com/workers/fragment-worker.mjs");
Rule: ALWAYS verify the worker URL resolves to a valid JavaScript module. NEVER use a worker URL from a different origin without CORS headers.
E-12: Boolean Operation Timeout
Error: Loading hangs indefinitely on certain IFC files, browser tab becomes unresponsive.
Cause: Complex CSG (Constructive Solid Geometry) boolean operations in the IFC file cause web-ifc to enter long-running computations. This is a known limitation with certain modeling software exports.
Fix:
await ifcLoader.setup();
ifcLoader.settings.webIfc.BOOL_ABORT_THRESHOLD = 5000; // Abort after 5 seconds
ifcLoader.settings.webIfc.USE_FAST_BOOLS = true; // Faster but less accurate
Rule: ALWAYS set BOOL_ABORT_THRESHOLD when loading untrusted or unknown IFC files. A threshold of 5000-10000ms prevents infinite hangs while allowing most boolean operations to complete.
E-13: Corrupt or Invalid IFC File
Error: Invalid IFC file, empty model, or parser crash.
Diagnostic checklist:
- Open the file in a text editor — does it start with
ISO-10303-21;? - Was the file fetched correctly? Check response status and content length.
- Was
response.text()used instead ofresponse.arrayBuffer()? Text decoding corrupts binary IFC data in some encodings. - Is the file an IFC-XML (
.ifcXML) file? web-ifc only supports STEP-encoded IFC.
Fix:
// ALWAYS use arrayBuffer, never text()
const response = await fetch(url);
if (!response.ok) throw new Error(`Fetch failed: ${response.status}`);
const buffer = await response.arrayBuffer();
if (buffer.byteLength === 0) throw new Error("Empty IFC file");
const data = new Uint8Array(buffer);
Rule: ALWAYS validate the response before loading. NEVER use response.text() for IFC files — ALWAYS use response.arrayBuffer().
E-14: WASM Memory Exhaustion
Error: Browser tab crashes, Out of memory, or RuntimeError: memory access out of bounds.
Cause: Very large IFC models (500MB+) or multiple models loaded simultaneously exhaust the WASM linear memory.
Fix:
// Set memory limit
ifcLoader.settings.webIfc.MEMORY_LIMIT = 2147483648; // 2GB
// Use streaming for large models instead of full load
// Filter unnecessary IFC classes
ifcLoader.onIfcImporterInitialized.add((importer) => {
importer.classes.elements.delete(WEBIFC.IFCFURNISHINGELEMENT);
importer.classes.elements.delete(WEBIFC.IFCSPACE);
});
// Dispose models when no longer needed
fragmentsManager.dispose();
Rule: ALWAYS filter IFC classes to reduce memory when loading large models. ALWAYS dispose models that are no longer needed.
Diagnostic Checklist: Loading Failures
When an IFC file fails to load, work through this checklist in order:
- Console errors? Check the browser console for specific error messages. Match to the table above.
- WASM initialized? Is
setup()called and awaited beforeload()? - Worker initialized? Is
fragmentsManager.init(workerURL)called before loading? - WASM path correct? Does the path end with
/? Do the files exist at that path? - Version match? Does the WASM file version match
npm ls web-ifc? - Data type correct? Is the IFC data a
Uint8Array? - File valid? Does it start with
ISO-10303-21;? Is the response status 200? - Render loop active? Is
components.init()called? - Model in scene? Is
model.objectadded toworld.scene.three? - Camera framed? Can the camera see the model bounds?
- Container sized? Does the container have non-zero dimensions?
- CORS/headers? Are COOP/COEP set for multi-threaded? Is the worker URL accessible?
Error Recovery Patterns
Graceful Fallback
try {
const model = await ifcLoader.load(data, true, name);
world.scene.three.add(model.object);
} catch (error) {
if (error.message.includes("unreachable")) {
console.error("WASM version mismatch — check web-ifc version");
} else if (error.message.includes("magic word")) {
console.error("WASM MIME type error — configure server for application/wasm");
} else {
console.error("IFC loading failed:", error.message);
}
}
Retry with Relaxed Settings
async function loadWithFallback(data: Uint8Array, name: string) {
try {
return await ifcLoader.load(data, true, name);
} catch (firstError) {
// Retry with relaxed boolean settings
ifcLoader.settings.webIfc.USE_FAST_BOOLS = true;
ifcLoader.settings.webIfc.BOOL_ABORT_THRESHOLD = 3000;
ifcLoader.settings.webIfc.COORDINATE_TO_ORIGIN = true;
return await ifcLoader.load(data, true, name);
}
}
Relationship to Other Skills
| Skill | Relationship |
|---|---|
thatopen-syntax-ifc-loading |
Normal loading workflow. Use this errors skill when loading fails. |
thatopen-core-web-ifc |
Low-level WASM engine. Error patterns E-01 through E-03 trace to web-ifc initialization. |
thatopen-core-fragments |
Fragment system. Error E-05 traces to FragmentsManager initialization. |
thatopen-errors-performance |
Performance-related issues (memory, speed). Complementary to E-12 and E-14. |
References
references/methods.md— Error types, messages, and fix patternsreferences/examples.md— Working fix examples: WASM, path, version, workerreferences/anti-patterns.md— Common mistakes that cause loading failures