Troubleshooting Guide

Quick Diagnostic Checklist

  1. Session server running? (curl http://localhost:3000/health)
  2. Plugin installed? (Check Dashboard > Plugins)
  3. Script tag in Custom HTML? (Dashboard > General)
  4. Browser cache cleared? (Ctrl+F5)
  5. Correct WebSocket URL?
  6. Firewall allowing port 3000?

Related documentation:

Common Issues

Watch Party Button Not Visible

Symptoms:

  • No group icon in the video player header
  • Panel doesn’t appear

Solutions:

  1. Check Custom HTML configuration
    • Go to Dashboard > General > Branding
    • Verify this line is in “Custom HTML body”:
      <script src="/OpenWatchParty/ClientScript"></script>
      
  2. Hard refresh the browser
    • Press Ctrl+F5 (Windows/Linux) or Cmd+Shift+R (Mac)
    • Or clear browser cache completely
  3. Check browser console
    • Press F12 to open developer tools
    • Look for errors in the Console tab
    • Common errors:
      • 404 - Script not found (plugin not installed)
      • CORS - WebSocket blocked (check CORS config)
  4. Verify plugin is installed
    • Dashboard > Plugins should show “OpenWatchParty”
    • Check Jellyfin logs for plugin load errors
  5. Validate automatic injection runtime (File Transformation)
    • Registration alone is not sufficient. Confirm callback execution in logs.
    • Look for OpenWatchParty logs:
      • Registered File Transformation pattern 'index.html' -> callback 'TransformIndexHtml'
      • Registered File Transformation pattern 'home-html\..*\.chunk\.js' -> callback 'TransformHomeChunkScript'
      • TransformIndexHtml invoked for file ...
      • TransformHomeChunkScript invoked for file ...
    • Validate script endpoint:
      curl -I http://localhost:8096/OpenWatchParty/ClientScript
      
    • If endpoint is reachable but callback logs never appear, keep manual Custom HTML injection enabled until integration is fixed.

Cannot Connect to Session Server

Symptoms:

  • “Offline” status in the panel
  • Console shows WebSocket errors

Solutions:

  1. Check server is running
    # Docker
    docker ps | grep session
    
    # Check health endpoint
    curl http://localhost:3000/health
    
  2. Check firewall
    # Test connection
    nc -zv localhost 3000
    
    # Open port (UFW)
    sudo ufw allow 3000/tcp
    
  3. Check WebSocket URL
    • Browser console will show the attempted URL
    • Should be ws://host:3000/ws or wss://host:3000/ws
  4. Check CORS
    • Session server logs show CORS errors
    • Set ALLOWED_ORIGINS to include your Jellyfin URL

Sync Issues

Symptoms:

  • Participants out of sync
  • Playback drifts apart over time
  • Frequent jumping or stuttering

Solutions:

  1. Wait a few seconds
    • Initial sync takes 2-3 seconds
    • Drift correction works gradually
  2. Host: pause and play again
    • This re-syncs all participants
  3. Check network quality
    • High latency causes sync issues
    • Check RTT in the Watch Party panel
    • Ideal RTT: < 100ms
  4. HLS/transcoding issues
    • Transcoded streams have higher latency
    • Try direct play if possible
    • Reduce quality if network is slow
  5. Check if everyone has the same media
    • Different versions may have different durations
    • Ensure all users can access the media

Technical details: See Architecture - Clock Skew Tolerance and Sync Algorithms

Room Closes Unexpectedly

Symptoms:

  • “Room closed” notification
  • Participants disconnected

Causes:

  1. Host disconnected
    • Host’s network dropped
    • Host closed the browser
    • Host’s computer went to sleep
  2. Server restart
    • Rooms are in-memory (ephemeral)
    • Check if server was restarted
  3. Network issues
    • Check host’s connection
    • Check server logs for errors

Technical details: See Architecture - Host Network Disconnect

Authentication Errors

Symptoms:

  • Cannot join rooms
  • “Unauthorized” errors
  • Token issues

Solutions:

  1. Check JWT configuration matches
    • Plugin JWT Secret must match server JWT_SECRET
    • Both must be configured or both must be empty
  2. Check token expiration
    • Default: 1 hour
    • Refresh the page to get a new token
  3. Rate limiting
    • Max 30 token requests per fixed one-minute window
    • Wait and try again

Jellyfin 12: every OpenWatchParty request returns 401

Symptoms:

  • The Watch Party panel loads but no request succeeds
  • 401 Unauthorized responses in the browser console or Jellyfin logs

Cause:

Jellyfin 12 disables legacy authorization. The DisableLegacyAuthorization migration turns off EnableLegacyAuthorization, so the legacy X-Emby-Token header no longer resolves and only Authorization: MediaBrowser Token="..." is accepted.

OpenWatchParty 0.4.0 (Jellyfin 12) and 0.3.4 (Jellyfin 10.11) send the modern Authorization header. 0.3.3 and earlier do not, so they cannot authenticate against Jellyfin 12.

Solutions:

  1. Upgrade OpenWatchParty
    • This is the supported fix. Install 0.4.0 on Jellyfin 12, or 0.3.4 on Jellyfin 10.11, from the plugin repository or manually.
    • Verify the installed version in Dashboard > Plugins > OpenWatchParty.
  2. Temporary stopgap only

    As a short-lived workaround, set the following in Jellyfin’s system.xml:

    <EnableLegacyAuthorization>true</EnableLegacyAuthorization>
    

    Then restart Jellyfin.

    This is deprecated and unsupported long term. It re-enables a legacy authentication path that Jellyfin 12 is removing and only restores access until you can upgrade. Do not rely on it.

The WebSocket connects but the session server rejects the token

Symptoms:

  • The OpenWatchParty panel loads but never joins a room
  • The session server logs Client connected: … immediately followed by Auth failed for …: Invalid token: InvalidSignature
  • The plugin diagnostics may report authentication_configuration as passing

Cause:

The plugin signs each session token with its own JwtSecret; the session server verifies it with JWT_SECRET. When the two values differ, every authentication attempt fails with InvalidSignature even though both components look healthy on their own.

The plugin’s Allow insecure unauthenticated development setting does not work around this. It only makes the plugin omit the token, it is ignored while a JwtSecret is configured, and the session server independently requires ALLOW_INSECURE_NO_AUTH=true before it accepts unauthenticated clients.

Solutions:

  1. Managed deployments (installed with owpctl): run owpctl doctor, which performs an authenticated WebSocket ping/pong and reports this failure directly. Use owpctl configure --rotate-jwt-secret (or owpctl pair) to bring both sides back in sync.
  2. Manual deployments: set the same value in Dashboard → Plugins → OpenWatchParty → JWT secret and in the session server’s JWT_SECRET environment variable, then restart the session server. Confirm from its logs that it started with JWT authentication is enabled and that no InvalidSignature appears after a browser reload.

Diagnostics report the session server as unreachable

Symptoms:

  • Run diagnostics fails the session_http check with SESSION_UNREACHABLE or Connection refused (host:3000)
  • The browser still appears to connect, or the panel times out while just up looks healthy

Cause:

The health probe runs inside the Jellyfin process, so it resolves the session server from Jellyfin’s network namespace — not the browser’s. A same-host auto-detected URL such as ws://192.168.1.10:3000/ws can be reachable from the browser and refused from the Jellyfin container, especially when the two run on different Docker networks or the port is only published on loopback.

Solutions:

  1. Set an explicit Session server URL (ws://host:port/ws) that is reachable from both Jellyfin and the browser, rather than relying on same-host auto-detection.
  2. In Docker, put Jellyfin and the session server on a shared network and use the service name (for example ws://owp-session-server:3000/ws) if the browser reaches it through a reverse proxy.
  3. Re-run Run diagnostics: session_http must report the session server version and protocol before a watch party can work.

HLS Streaming Issues

Symptoms:

  • Sync works initially but drifts during playback
  • Frequent buffering interrupts sync
  • Position jumps backward unexpectedly
  • “False pauses” trigger unwanted sync events

Understanding HLS:

HLS (HTTP Live Streaming) breaks video into small segments (typically 2-10 seconds). This causes:

  • Buffering gaps between segments
  • Position reporting delays
  • readyState changes during segment loads

Solutions:

  1. Buffering during sync
    Problem: Video buffers, reports paused state, triggers sync issues
    Solution: OpenWatchParty filters these "false pauses" automatically
    If issues persist: reduce video quality to improve buffering
    
  2. Position jumps backward
    Problem: HLS reports position from previous segment during load
    Solution: Server ignores small backward jumps (< 2s) automatically
    If large jumps: check network stability, try different quality
    
  3. Segment loading delays
    • Reduce bitrate/quality in Jellyfin playback settings
    • Use direct play instead of transcoding when possible
    • Check network bandwidth between client and Jellyfin server
  4. Direct play vs transcoding
    # Check if transcoding is happening
    # In Jellyfin Dashboard > Playback > Active Devices
    # Look for "Transcoding" indicator
    
    # For better sync, prefer:
    # - Direct Play (no transcoding)
    # - Direct Stream (container change only)
    # Avoid if possible:
    # - Transcoding (full re-encode)
    
  5. Safari-specific HLS issues
    • Safari uses native HLS (not hls.js like other browsers)
    • May report readyState differently during buffering
    • Workaround: Keep Safari tab in focus, or use Chrome/Firefox

Technical details: See Sync Algorithms - HLS Handling

Rate Limiting Issues

Symptoms:

  • “Rate limit exceeded” error
  • 429 HTTP status code
  • Cannot get new token
  • Messages being dropped

Types of rate limiting:

Limit Value Applies To
Token requests 30/min Per user, fixed one-minute window
WebSocket messages 30/sec Per client connection
Message size 64 KB Per message

Solutions:

  1. Token rate limit (30/min)
    Cause: Too many page refreshes or reconnection attempts
    Solution: Wait 1 minute, then refresh once
    Prevention: Don't rapidly refresh the page
    
  2. Message rate limit (30/sec)
    Cause: Rapid playback actions (spam play/pause/seek)
    Solution: Slow down interactions
    Note: Normal usage won't hit this limit
    
  3. Debugging rate limits
    # Check server logs for rate limit messages
    docker logs session-server 2>&1 | grep -i "rate"
    
    # Look for:
    # "Rate limit exceeded for client X"
    # "Message dropped due to rate limit"
    
  4. If rate limited frequently
    • Check for browser extensions that might cause extra requests
    • Check for scripts auto-refreshing the page
    • Verify you’re not running multiple tabs with OpenWatchParty

Panel Opens But Empty

Symptoms:

  • Panel slides out but shows nothing
  • No room list

Solutions:

  1. Wait for connection
    • WebSocket may still be connecting
    • Check for “Connecting…” status
  2. Check console for JavaScript errors
    • Press F12 and check Console tab
    • Look for script loading errors
  3. Clear browser cache
    • Old script version may be cached

Log Analysis

Session Server Logs

# Docker logs
docker logs session-server

# Follow logs
docker logs -f session-server

What to look for:

Log Message Meaning
Client connected New WebSocket connection
Client disconnected Connection closed
Room created New room started
Room closed Room ended
SECURITY: Wildcard origin CORS warning
Message too large Size limit exceeded
Invalid token Authentication failure

Jellyfin Logs

Location varies by installation:

  • Docker: docker logs jellyfin
  • Linux: /var/log/jellyfin/
  • Windows: %ProgramData%\Jellyfin\Server\log\

Look for:

[OpenWatchParty] JWT authentication is enabled.
[OpenWatchParty] JwtSecret is not configured.

Browser Console

  1. Press F12 to open Developer Tools
  2. Go to Console tab
  3. Filter by “OWP” or “OpenWatchParty”

Common messages:

Message Meaning
[OWP] Loaded Client initialized
[OWP] Connected WebSocket connected
[OWP] Disconnected WebSocket closed
[OWP] Room joined Successfully joined room

Network Debugging

Check WebSocket Connection

In browser console:

// Check if connected
console.log(OWP.state.ws?.readyState);
// 0 = CONNECTING, 1 = OPEN, 2 = CLOSING, 3 = CLOSED

Test Session Server

# Health check
curl http://localhost:3000/health

# WebSocket test (requires wscat)
npm install -g wscat
wscat -c ws://localhost:3000/ws

Check Network Traffic

  1. Open Developer Tools (F12)
  2. Go to Network tab
  3. Filter by “WS” for WebSocket
  4. Click on the WebSocket connection
  5. View Messages to see all communication

Performance Issues

High CPU Usage

Session Server:

  • Check number of rooms/clients
  • Consider scaling (future feature)

Client:

  • Reduce video quality
  • Close other tabs
  • Check for JavaScript errors

Memory Usage

Session Server:

  • Rooms are in-memory
  • Each client: ~1KB
  • Each room: ~5KB + clients
  • Restart to clear if needed

Slow Sync

  • Reduce SYNC_LEAD_MS if latency is low
  • Increase if latency is high
  • Check client hardware (old browsers may struggle)

Getting Help

Information to Provide

When reporting issues, include:

  1. Environment
    • Jellyfin version
    • Browser and version
    • Operating system
    • Docker version (if applicable)
  2. Configuration
    • Session server settings (without secrets!)
    • Plugin configuration
    • Reverse proxy setup
  3. Logs
    • Session server logs
    • Jellyfin logs
    • Browser console output
  4. Steps to Reproduce
    • What you did
    • What you expected
    • What happened instead

Where to Get Help

Reset Procedures

Reset Client State

  1. Clear browser cache and cookies
  2. Hard refresh (Ctrl+F5)
  3. Or in console:
    localStorage.clear();
    location.reload();
    

Reset Server State

# Restart session server (clears all rooms)
docker restart session-server

Reset Plugin Configuration

  1. Dashboard > Plugins > OpenWatchParty
  2. Clear all fields
  3. Save
  4. Restart Jellyfin

Complete Reset

  1. Stop all services
  2. Remove plugin DLL
  3. Clear Jellyfin config cache
  4. Reinstall from scratch

Back to top

OpenWatchParty - Synchronized watch parties for Jellyfin