| id | howto-debug-bundle | |||||
|---|---|---|---|---|---|---|
| type | how-to | |||||
| status | current | |||||
| tags |
|
Two complementary tools work together to diagnose stream failures:
iptv-tunerr debug-bundle— collects Tunerr-side state (recent stream attempts, provider profile, CF learned state, cookie metadata, env vars) into a directory or tarball.scripts/analyze-bundle.py— ingests that directory (plus optionally PMS.log, Tunerr stdout log, and a pcap capture) and produces a ranked findings report.
Together they turn "I don't know why this channel fails" into "here are the top 3 findings with evidence."
| File | Source | Description |
|---|---|---|
stream-attempts.json |
Live server /debug/stream-attempts.json |
Last 500 stream attempts: channel, UA used, HTTP status, CF block flag, bytes |
provider-profile.json |
Live server /provider/profile.json |
Provider autopilot state: learned tuner cap, CF block hits, penalized hosts, HLS instability |
cf-learned.json |
IPTV_TUNERR_CF_LEARNED_FILE or beside jar |
Per-host: working UA found by cycling, CF-tagged flag, timestamp |
cookie-meta.json |
IPTV_TUNERR_COOKIE_JAR_FILE |
Cookie names, domains, expiry — no cookie values (safe to share) |
env.json |
Process environment | All IPTV_TUNERR_* vars, secrets (_PASS, _TOKEN, _KEY, _USER) redacted |
bundle-info.json |
Generated | Timestamp, version, collection summary |
# Collect from running server (default: http://localhost:5004)
iptv-tunerr debug-bundle
# Custom server URL and output directory
iptv-tunerr debug-bundle -url http://mytuner:5004 -out ./debug-scratch
# Also create a shareable .tar.gz
iptv-tunerr debug-bundle -out ./debug-scratch --tar
# Offline only (no live server — just local state files)
iptv-tunerr debug-bundle -out ./debug-scratch --no-server| Flag | Default | Description |
|---|---|---|
-url |
http://localhost:5004 |
Base URL of running Tunerr server |
-out |
debug-scratch/ |
Output directory (created if needed) |
--tar |
false | Also write tunerr-debug-TIMESTAMP.tar.gz |
--redact |
true | Redact _PASS/_TOKEN/_KEY/_USER from env vars |
--no-server |
false | Skip live server fetch; only collect local state files |
cookie-meta.jsoncontains only cookie names, domains, paths, and expiry timestamps — never the cookie values. Safe to include in bug reports.- Secrets are redacted from
env.jsonby default. If you need the full env for debugging your own setup locally, use--redact=false(but do not share the result). - The
debug-scratch/default output directory is also the default input foranalyze-bundle.py, so the two tools work together without extra flag-passing.
Auto-detects log files in a directory, parses them, normalizes timestamps to UTC, and runs a pattern-matching finding engine. Output is a ranked report of what went wrong.
- Python 3.8+
tshark(from Wireshark) — only required if you have a.pcapor.pcapngfile to analyze. Install withapt install tsharkorbrew install wireshark. Optional: the script works without it for the other sources.
| File type | Detection | What's extracted |
|---|---|---|
| Tunerr JSONL stream attempts | Content-sniffed for capsule_id/channel_id JSON fields |
CF blocks, HTTP statuses, UA used, bytes |
| Tunerr stdout log | Content-sniffed for [iptv-tunerr] prefix |
Gateway events, CF bootstrap events, UA cycling results |
| Plex Media Server log | Content-sniffed for Plex Media Server header or plex.tv in content |
DVR tune/stop events, /stream/ HTTP calls |
| pcap capture | .pcap/.pcapng extension |
On-wire HTTP requests (UA), HTTP response status, JA3 TLS fingerprints |
cf-learned.json |
Filename match | Per-host CF state |
cookie-meta.json or cookie jar JSON |
Filename/content match | cf_clearance presence, expiry |
# Analyze everything in ./debug-scratch/
python3 scripts/analyze-bundle.py ./debug-scratch/
# Save report to file
python3 scripts/analyze-bundle.py ./debug-scratch/ --output report.txt
# Machine-readable JSON output
python3 scripts/analyze-bundle.py ./debug-scratch/ --json
# Override specific file paths (auto-detection still runs for the rest)
python3 scripts/analyze-bundle.py ./debug-scratch/ \
--pms /var/log/plex/Plex\ Media\ Server.log \
--pcap /tmp/capture.pcap| Finding | What it means |
|---|---|
CF_BLOCK_UNRESOLVED |
CF block seen in stream attempts, no working UA in cf-learned.json |
CF_BLOCK_RESOLVED |
CF block seen but UA cycling found a working UA (informational — it worked) |
CF_HOST_NO_WORKING_UA |
Host is CF-tagged in cf-learned.json but no working UA is stored |
CF_CLEARANCE_EXPIRED |
cf_clearance cookie in jar has passed its expiry time |
UA_MISMATCH_PCAP |
On-wire UA from pcap differs from Tunerr log — suggests proxy/MITM rewriting headers |
TLS_FINGERPRINT_GO_STDLIB |
Go stdlib JA3 fingerprint detected in pcap — CF may still score bot even with correct UA |
PLEX_TUNE_NO_TUNERR_RECV |
Plex log shows a tune request but Tunerr log shows no corresponding stream start |
PLEX_STOP_NO_TUNERR_STREAM |
Plex log shows session stop with no prior Tunerr stream events for that channel |
STREAM_FAILURES |
High failure rate in stream attempts for a specific channel or host |
- Sources detected — what files were found and parsed
- Findings — ranked by severity (error > warning > info), each with confidence score and evidence events
- pcap notes — JA3 fingerprints seen, known Go stdlib fingerprint detection
- CF learned state — per-host: CF-tagged, cf_clearance present/TTL, working UA
- Cookie jar metadata — which cookies are present, their expiry
- Event timeline — last 60 events across all sources, normalized to UTC
0— no error-severity findings1— one or more error-severity findings found (useful for CI/scripted analysis)
This is the recommended workflow when you have a reproducible stream failure and want to get the most complete diagnosis.
Before reproducing the failure:
# Collect Tunerr state (run this while Tunerr is running)
iptv-tunerr debug-bundle --out ./debug-scratch
# If you have tcpdump available, capture on-wire traffic
# (capture on the interface Tunerr uses for outbound provider requests)
tcpdump -i eth0 -w ./debug-scratch/capture.pcap &In Plex, try to play the failing channel. Let it fail, or play for ~30 seconds.
# Stop tcpdump
kill %1
# Copy Plex log (adjust path for your platform)
cp /var/lib/plexmediaserver/Library/Application\ Support/Plex\ Media\ Server/Logs/Plex\ Media\ Server.log \
./debug-scratch/Plex\ Media\ Server.log
# Copy Tunerr stdout log if you are redirecting it
cp /var/log/iptvtunerr/tunerr.log ./debug-scratch/tunerr.log
# or use journalctl:
journalctl -u iptvtunerr --since "5 minutes ago" > ./debug-scratch/tunerr.logpython3 scripts/analyze-bundle.py ./debug-scratch/ --output report.txt
cat report.txtiptv-tunerr debug-bundle --out ./debug-scratch --tar
# Share: tunerr-debug-TIMESTAMP.tar.gz + report.txt
# The tarball does NOT contain pcap (too large) or PMS.log (potentially private)
# Attach those separately only if askedFinding: CF_BLOCK_UNRESOLVED (error, confidence: 0.95)
Evidence: 5 stream attempts → HTTP 403/503, cf_block=true
cf-learned.json: host is cf_tagged, working_ua=""
Action: Run iptv-tunerr cf-status to confirm no learned UA. If cycling failed, try manual cookie import. See cloudflare-bypass.md.
Finding: TLS_FINGERPRINT_GO_STDLIB (warning, confidence: 0.8)
JA3 in pcap: 771,49195-49199-... (known Go stdlib pattern)
This means CF might score your requests as a bot even if the UA is correct. The only current workaround is importing a browser's cf_clearance cookie. TLS fingerprint spoofing (utls) is a future work item.
Finding: PLEX_TUNE_NO_TUNERR_RECV (warning, confidence: 0.7)
Plex log: DVR tune at 2026-03-19T14:32:01Z channel 105
Tunerr log: no /stream/ request in ±30s window
Suggests the tuner URL Plex is using is stale or wrong. Check IPTV_TUNERR_BASE_URL and whether Plex's registered tuner points at the right host:port.
Finding: UA_MISMATCH_PCAP (error, confidence: 0.85)
Tunerr log: user_agent="Mozilla/5.0 (Firefox)"
On-wire pcap: User-Agent: IptvTunerr/1.0
Something between Tunerr and the provider is rewriting the User-Agent. Check for transparent proxies, nginx reverse proxies, or Docker networking that might strip headers.
- cloudflare-bypass.md — how to fix CF blocks
- cli-and-env-reference.md — full env var reference
- iptvtunerr-troubleshooting.md — general troubleshooting runbook