# How to Debug Failed IPTV Stream Tests: A Complete Guide

> Debug failed IPTV stream tests with npm run playlist:test. Inspect errors like TIMEOUT or HTTP 404 and use NODE_ENV=test with mock data for reliable reproduction.

- Repository: [iptv-org/iptv](https://github.com/iptv-org/iptv)
- Tags: how-to-guide
- Published: 2026-02-25

---

**To debug failed IPTV stream tests, run `npm run playlist:test`, inspect the live status table for error codes like `TIMEOUT` or `HTTP_404_NOT_FOUND`, and use `NODE_ENV=test` with mock data for deterministic reproduction.**

The `iptv-org/iptv` repository uses an automated testing suite to validate thousands of stream URLs across its playlist files. When the `playlist:test` command flags streams as failed, understanding the underlying error classification system and debugging tools will help you identify whether a link is temporarily down, permanently moved, or malformed.

## Understanding the IPTV Stream Test Architecture

The testing pipeline relies on three core components working sequentially: network requests via **axios**, media analysis via **mediainfo.js**, and error normalization in the `StreamTester` class.

### Core Testing Components

In [`scripts/core/streamTester.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/core/streamTester.ts), the `test()` method orchestrates the validation:

1. **Network Request**: Fetches the stream URL with configurable timeouts and proxy support.
2. **Media Analysis**: Passes the response buffer to [`mediainfo.js`](https://github.com/iptv-org/iptv/blob/main/mediainfo.js) to detect video tracks.
3. **Result Classification**: Returns a `StreamTesterResult` object containing an `ok` boolean and a specific error code.

### Error Classification System

The [`scripts/commands/playlist/test.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/commands/playlist/test.ts) file defines `errorStatusCodes`, an array that determines which failures constitute critical errors versus warnings:

```ts
const errorStatusCodes = [
  'ECONNREFUSED',
  'ENOTFOUND',
  'ENETUNREACH',
  'EPROTO',
  'HTTP_404_',
  'HTTP_404_NOT_FOUND',
  'HTTP_404_UNKNOWN_ERROR',
  'HTTP_410_GONE'
];

```

Streams matching these codes without a `label` property increment the error counter; labeled streams generate warnings instead.

## Running the Test and Interpreting Results

Execute the validation against specific playlist files using the npm script defined in [`package.json`](https://github.com/iptv-org/iptv/blob/main/package.json):

```bash
cross-env DATA_DIR=tests/__data__/input/data ROOT_DIR=tests/__data__/output \
npm run playlist:test streams/ag.m3u

```

The command renders a **live table** that updates every few seconds with the following columns:

- **tvg-id**: The stream identifier from the playlist.
- **url**: The truncated stream URL.
- **label**: Optional human-readable metadata.
- **status**: The result code (`OK`, `TIMEOUT`, `HTTP_404_NOT_FOUND`, `NO_VIDEO`, etc.).

Upon completion, the CLI outputs a summary such as `2 problems (1 errors, 1 warnings)`. Red entries in the table indicate streams that triggered the failure.

## Identifying Common Failure Reasons

### Network and HTTP Errors

In [`scripts/core/streamTester.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/core/streamTester.ts) (lines 96-107), the error handler normalizes axios exceptions into predictable codes:

- **`TIMEOUT`**: Triggered when a request exceeds the configured timeout or is explicitly canceled.
- **`HTTP_<status>_<text>`**: Derived from `error.response.status` and `statusText` (e.g., `HTTP_404_NOT_FOUND`).
- **`AXIOS_<code>`**: Captures low-level network errors like `ECONNREFUSED` or `ENOTFOUND` when no response is received.

### Media Analysis Failures

Even when a URL responds successfully, the stream must contain valid video tracks. The [`mediainfo.js`](https://github.com/iptv-org/iptv/blob/main/mediainfo.js) analysis (lines 78-91) returns:

- **`OK`**: At least one video track detected.
- **`NO_VIDEO`**: The response parsed successfully but contained no video streams (common for radio streams or corrupted playlists).

## Debugging Techniques for Failed Streams

### Using Verbose Logging and Isolation

To inspect the raw `StreamTesterResult` for a specific stream, temporarily add logging to the `runTest` function in [`scripts/commands/playlist/test.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/commands/playlist/test.ts):

```ts
async function runTest(stream: Stream) {
  const result = await tester.test(stream);
  console.log(`URL: ${stream.url}, Result:`, result);
  // ...existing logic...
}

```

For easier reading, limit parallelism to one stream at a time:

```bash
npm run playlist:test streams/ag.m3u -- --parallel 1

```

### Testing Mode with Mock Data

Set `NODE_ENV=test` to bypass network requests and use deterministic mock data from [`tests/__data__/input/playlist_test/results.js`](https://github.com/iptv-org/iptv/blob/main/tests/__data__/input/playlist_test/results.js):

```bash
cross-env NODE_ENV=test DATA_DIR=tests/__data__/input/data \
npm run playlist:test streams/ag.m3u

```

In this mode, [`scripts/core/streamTester.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/core/streamTester.ts) (line 58) imports the mock map:

```ts
if (TESTING) {
  const results = (await import('../../tests/__data__/input/playlist_test/results.js')).default;
  return results[stream.url as keyof typeof results];
}

```

Edit [`results.js`](https://github.com/iptv-org/iptv/blob/main/results.js) to simulate specific error conditions without external dependencies:

```js
export default {
  "https://example.com/broken.m3u8": { status: { ok: false, code: "HTTP_404_NOT_FOUND" } },
  "https://example.com/good.m3u8": { status: { ok: true, code: "OK" } }
};

```

### Automatic Cleanup with --fix Flag

Once you have confirmed which streams are permanently broken, use the `--fix` flag to automatically remove them:

```bash
npm run playlist:test streams/ag.m3u -- --fix

```

This invokes `removeBrokenLinks()` (lines 55-64 in [`scripts/commands/playlist/test.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/commands/playlist/test.ts)), which:

1. Groups streams by their source playlist file.
2. Filters out streams where `isBroken(stream)` returns `true`.
3. Overwrites the original playlist files with the cleaned entries.

The `isBroken()` function (lines 12-18) applies the same logic as the error counter, ensuring only unlabeled streams with critical error codes are purged.

## Summary

- **Run tests** with `npm run playlist:test <playlist>` to generate a live status table showing `OK`, `TIMEOUT`, `HTTP_404_NOT_FOUND`, and other codes.
- **Interpret failures** by comparing status codes against the `errorStatusCodes` array in [`scripts/commands/playlist/test.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/commands/playlist/test.ts) to distinguish critical errors from warnings.
- **Debug efficiently** by adding temporary logging to `runTest()`, using `--parallel 1` for serial output, or setting `NODE_ENV=test` to use mock data from [`tests/__data__/input/playlist_test/results.js`](https://github.com/iptv-org/iptv/blob/main/tests/__data__/input/playlist_test/results.js).
- **Clean playlists** automatically with the `--fix` flag, which triggers `removeBrokenLinks()` to purge streams that return codes like `HTTP_410_GONE` or `ECONNREFUSED`.

## Frequently Asked Questions

### Why does a stream show HTTP_404_NOT_FOUND when it works in my browser?

The `HTTP_404_NOT_FOUND` code indicates the server returned a 404 status to the axios request in [`scripts/core/streamTester.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/core/streamTester.ts). This often happens when the server blocks automated requests by checking for specific headers or user-agents that the test client does not send. Try comparing the headers your browser sends with the default axios configuration, or check if the stream requires a referer or specific cookie that the test environment lacks.

### How do I debug a specific stream without running the entire playlist?

Set `NODE_ENV=test` and edit the [`tests/__data__/input/playlist_test/results.js`](https://github.com/iptv-org/iptv/blob/main/tests/__data__/input/playlist_test/results.js) file to include only the URL you want to debug. Then run the test command with `--parallel 1` to process streams serially. This isolates the output for your target stream without network variability, allowing you to verify how the CLI handles specific error codes like `NO_VIDEO` or `TIMEOUT`.

### What is the difference between an error and a warning in the test output?

Errors are counted when a stream returns a code listed in `errorStatusCodes` (such as `HTTP_404_NOT_FOUND` or `ECONNREFUSED`) and has no `label` property. Warnings are generated for the same error codes if the stream has a label, or for non-critical issues. The `--fix` flag only removes streams classified as errors, preserving labeled streams even if they fail, according to the logic in `isBroken()` within [`scripts/commands/playlist/test.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/commands/playlist/test.ts).

### Can I use a proxy to debug geo-blocked streams?

Yes, pass the `-x` or `--proxy` flag followed by your proxy URL when running the test command. The `StreamTester` class passes this option to the axios client in [`scripts/core/streamTester.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/core/streamTester.ts), routing all requests through the specified proxy. If all streams suddenly return `TIMEOUT` after adding the flag, verify the proxy is running and accessible from your environment.