# How to Handle Broken or Invalid Stream URLs in IPTV Playlists: The Free-TV/IPTV Workflow

> Learn how to handle broken IPTV stream URLs in Free-TV/IPTV playlists. Mark invalid channels and regenerate your M3U8 playlist for verified streams.

- Repository: [Free TV/IPTV](https://github.com/Free-TV/IPTV)
- Tags: how-to-guide
- Published: 2026-06-26

---

**Mark broken channels by replacing the `[>]` marker with `[x]` in the country-specific Markdown files, then regenerate the playlist using [`make_playlist.py`](https://github.com/Free-TV/IPTV/blob/main/make_playlist.py) to ensure only verified streams appear in the final M3U8 output.**

The Free-TV/IPTV repository maintains a curated collection of public IPTV channels through a unique Markdown-based workflow. To handle broken or invalid stream URLs in IPTV playlists effectively, the project uses a simple marker system that filters out dead links during the automated build process. This approach ensures that end users receive only working streams in the generated `playlist.m3u8` file.

## How the Validation System Works

### The `[>]` and `[x]` Marker Convention

The repository stores channel definitions in per-country Markdown files located in the `lists/` directory. Each channel entry follows a strict table format where the **URL column** determines inclusion in the final playlist:

- **`[>]`** — Indicates a verified, working stream URL that should be included in the output
- **`[x]`** or **`[x]()`** — Marks a broken or invalid stream that should be excluded

When contributors identify a non-functional stream, they move the channel to an "Invalid" category within the appropriate country file and replace the `[>]` marker with `[x]`. This convention preserves the historical data while ensuring the URL never reaches production playlists.

### The Channel Class and Parsing Logic

The [`make_playlist.py`](https://github.com/Free-TV/IPTV/blob/main/make_playlist.py) script processes these Markdown files using a dedicated `Channel` class that extracts metadata from each table row. The parser reads every line of the country files, extracts group titles from `<h1>` HTML tags, and instantiates `Channel` objects only for entries marked as valid.

## Step-by-Step: Removing Broken Streams from Playlists

Follow this workflow when you encounter a broken stream URL:

1. **Locate the channel** in the appropriate `lists/[country_code].md` file
2. **Move the entry** to the "Invalid" section of that file to maintain organization
3. **Replace the marker** — Change `[>]` to `[x]` in the URL column (use `[x]()` if leaving the URL empty)
4. **Submit changes** — Create a pull request; the CI pipeline will automatically regenerate `playlist.m3u8`

## The Build Script Filtering Logic

The core filtering mechanism resides in [`make_playlist.py`](https://github.com/Free-TV/IPTV/blob/main/make_playlist.py). The script explicitly skips any line lacking the `[>]` marker before processing it as a valid channel:

```python

# make_playlist.py – lines 50-55

for line in markup_file:
    if "<h1>" in line.lower() and "</h1>" in line.lower():
        group = re.sub('<[^<>]+>', '', line.strip())
    if "[>]" not in line:          # <-- only keep verified streams

        continue
    channel = Channel(group, line, country_code)
    m3u_line = channel.to_m3u_line()
    print(m3u_line, file=playlist)

```

This guard clause ensures that **invalid entries are completely ignored** during the build process. The `continue` statement prevents the script from ever instantiating a `Channel` object for broken URLs, meaning no `#EXTINF` entry gets written to the output file.

## Why This Approach Keeps Playlists Clean

The marker-based system provides several technical advantages for maintaining IPTV playlists at scale:

- **Zero broken links in output**: Because [`make_playlist.py`](https://github.com/Free-TV/IPTV/blob/main/make_playlist.py) filters at the parsing level, dead URLs never propagate to `playlist.m3u8` or country-specific playlist files
- **Audit trail preservation**: Using `[x]` instead of deletion retains the original URL and metadata, allowing future contributors to re-verify and reactivate the channel if it comes back online
- **Automated CI integration**: The filtering happens during every automated build, ensuring human error (forgetting to mark broken streams) gets caught before deployment

## Summary

- **Use `[x]`** to mark broken or invalid stream URLs in the `lists/*.md` files
- **The [`make_playlist.py`](https://github.com/Free-TV/IPTV/blob/main/make_playlist.py) script** automatically filters out any line without the `[>]` marker, preventing broken URLs from reaching the final M3U8 output
- **Preserve historical data** by moving channels to "Invalid" sections rather than deleting them entirely
- **Continuous Integration** handles playlist regeneration automatically once markers are updated

## Frequently Asked Questions

### What happens if a broken stream keeps the `[>]` marker?

If a contributor forgets to replace `[>]` with `[x]`, the invalid URL will be included in the next build of `playlist.m3u8`. This creates a poor user experience as IPTV players will attempt to load a dead stream. The repository relies on community vigilance to ensure markers are updated promptly when streams fail.

### Can I delete broken channels instead of marking them with `[x]`?

While physically possible, deletion is discouraged. The Free-TV/IPTV contribution guidelines recommend keeping entries with `[x]` markers because streams sometimes come back online after temporary outages. Preserving the URL metadata allows future contributors to easily reactivate the channel by simply changing the marker back to `[>]`.

### How does the parser distinguish between markers in different columns?

The [`make_playlist.py`](https://github.com/Free-TV/IPTV/blob/main/make_playlist.py) script performs a simple string search for `"[>]"` on each line of the Markdown file. It does not validate column position specifically, so markers must be placed carefully according to the established table format. The script assumes any line containing `[>]` represents a valid channel entry, regardless of which column technically contains the marker.

### Does the repository automatically detect broken URLs?

No, the current implementation does not include automated URL health checking. The system relies entirely on manual curation by contributors who verify streams and update markers accordingly. The `if "[>]" not in line: continue` logic in [`make_playlist.py`](https://github.com/Free-TV/IPTV/blob/main/make_playlist.py) serves as a passive gatekeeper rather than an active validation service.