Error Handling
Quantum Forge's WASM module throws typed JavaScript errors when operations fail. These are standard Error objects that you can catch, inspect, and handle gracefully in your game.
Error Types
All errors thrown by the WASM module are Error instances with a message prefix identifying the error type:
| Prefix | Meaning | Common cause |
|---|---|---|
[QuantumForgeStateSizeError] | State vector would exceed the maximum size | Too many entangled qudits; tensor product too large |
[QuantumForgeOutOfMemoryError] | WASM memory allocation failed | WASM heap exhausted |
[QuantumForgeError] | General quantum operation error | Invalid forced measurement outcome, destroyed property, cross-simulation entanglement |
Catching errors
const m = manager.getModule();
try {
m.i_swap(prop1, prop2, 0.5);
} catch (e) {
if (e instanceof Error) {
if (e.message.startsWith("[QuantumForgeStateSizeError]")) {
// State vector too large — fall back to classical
console.warn("Quantum state too large, skipping entanglement");
} else if (e.message.startsWith("[QuantumForgeOutOfMemoryError]")) {
// WASM heap exhausted — serious, consider clearing state
console.error("WASM out of memory");
} else if (e.message.startsWith("[QuantumForgeError]")) {
// General error
console.error("Quantum operation failed:", e.message);
}
}
}Matching by prefix
A helper pattern for cleaner error handling:
function isQuantumError(e: unknown, type: "StateSizeError" | "OutOfMemoryError" | "Error"): boolean {
return e instanceof Error && e.message.startsWith(`[QuantumForge${type}]`);
}
try {
m.i_swap(prop1, prop2, 0.5);
} catch (e) {
if (isQuantumError(e, "StateSizeError")) {
// handle gracefully
} else {
throw e; // unexpected error, re-throw
}
}Proactive OOM Guard
The WASM module estimates the result size of tensor product operations before allocating memory. If the result would exceed the maximum state size (100,000 basis amplitudes), the operation throws [QuantumForgeStateSizeError] without allocating.
This is a significant safety improvement. Previously, exceeding the state size limit would crash the WASM module entirely, requiring a page reload. Now the operation fails cleanly, and you can catch and handle it.
What triggers the guard
The guard fires when tensor_state() is called internally — which happens when a gate or i_swap connects two properties that are in separate (non-entangled) state vectors. The module estimates the tensor product size and rejects it if it would exceed the limit.
// prop1 is in a state vector with 500 basis amplitudes
// prop2 is in a separate state vector with 300 basis amplitudes
// Tensor product would be up to 500 * 300 = 150,000 amplitudes
// This exceeds 100,000 → throws StateSizeError BEFORE allocating
try {
m.i_swap(prop1, prop2, 0.5);
} catch (e) {
if (isQuantumError(e, "StateSizeError")) {
// State too large. Original states are untouched
// Fall back to classical behavior
}
}The key guarantee: when the guard fires, no state is modified. Both properties remain in their original, separate state vectors. You can continue using them independently.
Combining with state budget queries
Use state budget queries to avoid hitting the guard in the first place:
const size1 = m.state_vector_size(prop1);
const size2 = m.state_vector_size(prop2);
const maxSize = getMaxStateSize(); // 100,000
if (size1 * size2 > maxSize) {
// Don't even try — we know it would fail
fallbackToClassical();
} else {
m.i_swap(prop1, prop2, 0.5);
}Previous Behavior
Before these changes, errors from the C++ layer would either:
- Crash the WASM module — the entire module becomes unusable, requiring a page reload
- Throw opaque values — raw WASM pointers (
numbertype) that couldn't be caught or inspected meaningfully
Both failure modes are eliminated. All WASM operations now throw proper Error objects that can be caught, logged, and handled without losing the module.
Warning: Destroying Entangled Properties
When you call sim.destroyProperty(prop) or prop.destroy() on a property that is entangled with others, the library emits a console warning:
[QuantumForge] Warning: destroying entangled property (qudit 2 in 4-qudit shared state).
Measurement will collapse entangled partners.This happens because destroying an entangled property requires measuring it, which collapses the shared quantum state and affects all entangled partners. Their superposition is partially or fully destroyed.
To avoid unintended collapse: uncompute the entanglement before destroying. For example, reverse the operations that created the entanglement:
// Entangle
m.i_swap(prop, ancilla, 0.5);
// ... use the entanglement ...
// Uncompute before destroying
m.i_swap(prop, ancilla, -0.5);
// Now ancilla is separable — destroying it won't affect prop
sim.destroyProperty(ancilla); // no warning, no collapseThe warning is informational — the operation still succeeds. But if you see this warning unexpectedly, it usually means an undo step was missed.
Design Pattern: Graceful Degradation
The recommended pattern is to treat quantum as an enhancement. When the quantum system can't handle an operation, fall back to classical behavior:
class QuantumRegistry extends QuantumPropertyManager {
/** Split a ball into an entangled pair, or skip if quantum budget is exhausted */
trySplit(originalId: string, newId: string): boolean {
const prop1 = this.getProperty(originalId);
if (!prop1) return false;
const prop2 = this.acquireProperty();
try {
this.getModule().i_swap(prop1, prop2, 0.5);
} catch (e) {
if (e instanceof Error && e.message.startsWith("[QuantumForgeStateSizeError]")) {
this.logger?.warn?.("State too large for split, staying classical");
this.releaseProperty(prop2, 0);
return false;
}
throw e; // unexpected error
}
this.setProperty(newId, prop2);
return true;
}
}This pattern keeps the game playable regardless of quantum state complexity. Quantum Pong uses this approach: when the state budget is exhausted, new ball splits are silently skipped, and the game continues with classical balls.