Troubleshooting#

This troubleshooting reference covers common CloudXR.js issues and first-pass diagnostics.

Common Symptoms and Fixes#

WebXR not available or no immersive session#

  • For HTTP testing on Quest, configure insecure-origin browser flags for your dev URL.

  • For HTTPS deployments, trust both web app and proxy certificates.

  • Confirm the exact URL, port, and protocol expected by your hosting mode.

Connection fails before stream starts#

  • Verify signaling endpoint, protocol (ws:// vs wss://), and port.

  • Confirm firewall and NAT rules for required TCP and UDP ports.

  • If using a proxy, validate target routing and certificate trust.

Signaling connection fails (error 0xC0F22202)#

The sample apps display this as "Signaling connection failed" in the connection status banner. The code is emitted whenever the WebSocket signaling channel between the client and the CloudXR Runtime (or its TLS proxy) cannot be established. The SDK surfaces it via StreamingError. Closely related codes:

Code

Meaning

0xC0F22202

Signaling connection failed (genericrefer to the causes below).

0xC0F22213

Signaling connection timeout.

0xC0F22214

Signaling setup failed.

Common causes, in rough order of likelihood:

  1. TLS certificate not trusted by the client. Browsers reject self-signed certificates whose subjectAltName does not match the hostname or IP the client reaches. Proxy logs show SSL handshake failure ... certificate unknown. Set CERT_HOSTNAMES to include every reachable address, delete the cached server.pem, and restart. Refer to WebSocket Proxy Setup.

  2. Browser blocked the request (Private Network Access). A page on a public origin (e.g. https://...github.io) calling a private-IP proxy needs the user to have granted local-network permission on the calling origin. The proxy already returns Access-Control-Allow-Private-Network with value true; the missing piece is typically the per-site browser permission.

  3. Proxy or runtime not running. Confirm docker ps shows the proxy container, and that the CloudXR Runtime is listening on the backend port (default 49100). The proxy logs Connection refused until the runtime is up.

  4. Wrong endpoint configuration in the client. Verify serverIP, serverPort, and useSecureConnection (or the proxy URL) match where the proxy and runtime are actually listening.

  5. Network reachability. Confirm the phone or headset is on the same LAN as the proxy host (no AP isolation, VPN-only routing, etc.). A failed ping from the device shell rules this category in or out.

TLS certificate rejected by client#

Typical symptoms include:

  • The client browser reports ERR_CERT_COMMON_NAME_INVALID.

  • The proxy logs SSL handshake failure ... certificate unknown.

The proxy’s auto-generated certificate covers localhost, 127.0.0.1, and ::1 only. Modern browsers reject self-signed certificates whose subjectAltName does not include the hostname or IP the client is reaching.

Set CERT_HOSTNAMES to include every address the proxy will be reached at (LAN IP, mDNS hostname, etc.), delete the cached server.pem, and restart the container. Refer to WebSocket Proxy Setup.

Browser blocks access to a LAN proxy#

Symptom in the browser console:

Permission was denied for this request to access the local address space.

Modern Chromium browsers block requests from a public origin to a private IP unless the server returns Access-Control-Allow-Private-Network with value true on its preflight and the user grants local-network permission for the calling site.

The supplied proxy sends the required response header automatically. If the browser still blocks the request, grant local-network access on the calling origin (the page issuing the request), not on the proxy URL. The simpler dev-time alternative is to host the WebXR application itself on the same private network as the proxy, which avoids the public-to-private boundary entirely.

Media connects but stream is unstable#

  • Check latency, jitter, and packet loss against Network Setup.

  • Reduce bitrate and/or stream resolution for constrained networks.

  • Verify that server GPU and encoder capacity are not saturated.

Hand Tracking Not Responsive#

  • Pause and resume immersive mode.

  • Restart the headset if behavior persists.

  • Confirm runtime and client are both actively streaming.

Connection Issues and Error Categories#

Signaling Errors (WebSocket)#

Typical indicators include connection refusal, timeouts, and signaling-stage failures.

Quick checks:

  • Verify server or proxy address and signaling port.

  • Ensure TCP signaling port is reachable.

  • Confirm firewall allows signaling traffic.

Media Connection Errors (WebRTC and UDP)#

Typical indicators include successful signaling but no media stream.

Quick checks:

  • Verify UDP media port forwarding and firewall rules.

  • Verify NAT endpoint or port configuration.

  • Configure STUN/TURN for restrictive networks.

Other Streaming Errors#

  • Check network quality and available bandwidth.

  • Confirm CloudXR Runtime is active and using the expected profile.

  • Review runtime logs for stream start and stop failures.

Working with Error Codes#

CloudXR.js reports technical error codes with stream failures. Capture the code and include it in bug reports.

onStreamStopped: (error?: CloudXR.StreamingError) => {
  if (error?.code) {
    const hexCode = '0x' + error.code.toString(16).toUpperCase();
    console.error(`${error.message} (${hexCode})`);
  }
}

NAT Debug Checklist#

  1. Validate external TCP signaling reachability.

  2. Validate external UDP media reachability.

  3. Confirm runtime is configured with public endpoint and external ports.

  4. If using mediaAddress in the client, confirm that the runtime was started with enable-ice disabled.

  5. Confirm client uses public endpoint values, not private LAN values.

  6. You can also consider STUN/TURN if direct NAT mapping is insufficient for your use case.

NAT Debugging Steps#

  1. Verify signaling port accessibility (TCP):

    nc -zv <public-ip> <signaling-port>
    
  2. Verify media port accessibility (UDP):

    nc -zv <public-ip> <media-port>
    
  3. Bidirectional UDP test:

    On the server:

    nc -u -l <internal-media-port>
    

    On the client:

    echo "test" | nc -u <public-ip> <external-media-port>
    

Network Performance Checks#

Bandwidth:

iperf3 -s
iperf3 -c <server-ip>

Latency:

ping <server-ip>

If latency, jitter, or packet loss exceed guidance, reduce streaming load and improve Wi-Fi or network quality before further debugging.