Troubleshooting Guide
Quick Diagnostic Checklist
- Session server running? (
curl http://localhost:3000/health) - Plugin installed? (Check Dashboard > Plugins)
- Script tag in Custom HTML? (Dashboard > General)
- Browser cache cleared? (Ctrl+F5)
- Correct WebSocket URL?
- Firewall allowing port 3000?
Related documentation:
- Architecture - Edge Cases - Expected behavior in various scenarios
- Security Guide - Authentication and CORS issues
- Configuration - Server and plugin settings
Common Issues
Watch Party Button Not Visible
Symptoms:
- No group icon in the video player header
- Panel doesn’t appear
Solutions:
- Check Custom HTML configuration
- Go to Dashboard > General > Branding
- Verify this line is in “Custom HTML body”:
<script src="/OpenWatchParty/ClientScript"></script>
- Hard refresh the browser
- Press Ctrl+F5 (Windows/Linux) or Cmd+Shift+R (Mac)
- Or clear browser cache completely
- 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)
- Verify plugin is installed
- Dashboard > Plugins should show “OpenWatchParty”
- Check Jellyfin logs for plugin load errors
- 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:
- Check server is running
# Docker docker ps | grep session # Check health endpoint curl http://localhost:3000/health - Check firewall
# Test connection nc -zv localhost 3000 # Open port (UFW) sudo ufw allow 3000/tcp - Check WebSocket URL
- Browser console will show the attempted URL
- Should be
ws://host:3000/wsorwss://host:3000/ws
- Check CORS
- Session server logs show CORS errors
- Set
ALLOWED_ORIGINSto include your Jellyfin URL
Sync Issues
Symptoms:
- Participants out of sync
- Playback drifts apart over time
- Frequent jumping or stuttering
Solutions:
- Wait a few seconds
- Initial sync takes 2-3 seconds
- Drift correction works gradually
- Host: pause and play again
- This re-syncs all participants
- Check network quality
- High latency causes sync issues
- Check RTT in the Watch Party panel
- Ideal RTT: < 100ms
- HLS/transcoding issues
- Transcoded streams have higher latency
- Try direct play if possible
- Reduce quality if network is slow
- 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:
- Host disconnected
- Host’s network dropped
- Host closed the browser
- Host’s computer went to sleep
- Server restart
- Rooms are in-memory (ephemeral)
- Check if server was restarted
- 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:
- Check JWT configuration matches
- Plugin JWT Secret must match server JWT_SECRET
- Both must be configured or both must be empty
- Check token expiration
- Default: 1 hour
- Refresh the page to get a new token
- 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 Unauthorizedresponses 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:
- Upgrade OpenWatchParty
- This is the supported fix. Install
0.4.0on Jellyfin 12, or0.3.4on Jellyfin 10.11, from the plugin repository or manually. - Verify the installed version in Dashboard > Plugins > OpenWatchParty.
- This is the supported fix. Install
-
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 byAuth failed for …: Invalid token: InvalidSignature - The plugin diagnostics may report
authentication_configurationas 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:
- Managed deployments (installed with
owpctl): runowpctl doctor, which performs an authenticated WebSocket ping/pong and reports this failure directly. Useowpctl configure --rotate-jwt-secret(orowpctl pair) to bring both sides back in sync. - Manual deployments: set the same value in Dashboard → Plugins → OpenWatchParty → JWT secret and in the session server’s
JWT_SECRETenvironment variable, then restart the session server. Confirm from its logs that it started withJWT authentication is enabledand that noInvalidSignatureappears after a browser reload.
Diagnostics report the session server as unreachable
Symptoms:
Run diagnosticsfails thesession_httpcheck withSESSION_UNREACHABLEorConnection refused (host:3000)- The browser still appears to connect, or the panel times out while
just uplooks 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:
- 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. - 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. - Re-run
Run diagnostics:session_httpmust 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
readyStatechanges during segment loads
Solutions:
- 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 - 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 - 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
- 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) - Safari-specific HLS issues
- Safari uses native HLS (not hls.js like other browsers)
- May report
readyStatedifferently 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:
- 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 - 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 - 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" - 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:
- Wait for connection
- WebSocket may still be connecting
- Check for “Connecting…” status
- Check console for JavaScript errors
- Press F12 and check Console tab
- Look for script loading errors
- 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
- Press F12 to open Developer Tools
- Go to Console tab
- 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
- Open Developer Tools (F12)
- Go to Network tab
- Filter by “WS” for WebSocket
- Click on the WebSocket connection
- 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_MSif latency is low - Increase if latency is high
- Check client hardware (old browsers may struggle)
Getting Help
Information to Provide
When reporting issues, include:
- Environment
- Jellyfin version
- Browser and version
- Operating system
- Docker version (if applicable)
- Configuration
- Session server settings (without secrets!)
- Plugin configuration
- Reverse proxy setup
- Logs
- Session server logs
- Jellyfin logs
- Browser console output
- Steps to Reproduce
- What you did
- What you expected
- What happened instead
Where to Get Help
- GitHub Issues - Bug reports
- GitHub Discussions - Questions
- Jellyfin Forums - Community help
Reset Procedures
Reset Client State
- Clear browser cache and cookies
- Hard refresh (Ctrl+F5)
- Or in console:
localStorage.clear(); location.reload();
Reset Server State
# Restart session server (clears all rooms)
docker restart session-server
Reset Plugin Configuration
- Dashboard > Plugins > OpenWatchParty
- Clear all fields
- Save
- Restart Jellyfin
Complete Reset
- Stop all services
- Remove plugin DLL
- Clear Jellyfin config cache
- Reinstall from scratch