Skip to content

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:

PrefixMeaningCommon cause
[QuantumForgeStateSizeError]State vector would exceed the maximum sizeToo many entangled qudits; tensor product too large
[QuantumForgeOutOfMemoryError]WASM memory allocation failedWASM heap exhausted
[QuantumForgeError]General quantum operation errorInvalid forced measurement outcome, destroyed property, cross-simulation entanglement

Catching errors

typescript
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:

typescript
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.

typescript
// 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:

typescript
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:

  1. Crash the WASM module — the entire module becomes unusable, requiring a page reload
  2. Throw opaque values — raw WASM pointers (number type) 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:

typescript
// 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 collapse

The 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:

typescript
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.

Powered by Quantum Forge