subhra74/xdm · error · Exception

Invalid response code

Error message

Invalid response code: {statusCode.Value}

What it means

MultiSourceHLSDownloader.ProbeTarget downloads the HLS manifest and, when the download fails, inspects captured HTTP error statuses via FindErrorStatus. If a status code was recorded it throws an Exception 'Invalid response code: N' with an inner HttpException carrying that status.

Solutions

  1. Read the inner HttpException's status code: 403/401 means refresh cookies or signed URLs from the browser, 404 means the manifest URL is stale
  2. Re-extract the m3u8 URL from the page; CDN playlists rotate and old URLs expire quickly
  3. Retry with backoff if the code is 429/5xx (rate limiting or transient server issues)
  4. Ensure required headers (Referer, User-Agent, Origin) captured with the video match what the CDN expects

Example fix

// before
throw new Exception($"Invalid response code: {statusCode.Value}",
    new HttpException(statusCode.Value.ToString(), null, statusCode.Value));
// after
var code = (int)statusCode.Value;
if (code == 403 || code == 401)
    throw new DownloadException(ErrorCode.AuthExpired, $"HLS manifest auth failed ({code}) - refresh URL/cookies");
throw new Exception($"Invalid response code: {statusCode.Value}",
    new HttpException(statusCode.Value.ToString(), null, statusCode.Value));
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight the manifest URL before probing
using (var resp = await http.GetAsync(manifestUrl))
{
    if (!resp.IsSuccessStatusCode)
        Log.Warn($"HLS manifest pre-check failed: {(int)resp.StatusCode}");
}

Try / catch

try
{
    downloader.ProbeTarget();
}
catch (Exception ex) when (ex.InnerException is HttpException he)
{
    int code = (int)he.StatusCode;
    if (code == 401 || code == 403) RefreshSignedUrl();
    else if (code == 429) await Task.Delay(TimeSpan.FromSeconds(30));
    throw;
}

Prevention

When it happens

Trigger: ProbeTarget (invoked while building the playlists dictionary) receives failed segment/manifest downloads and FindErrorStatus() returns a known HTTP error status, e.g. 403/404 from the HLS server.

Common situations: HLS master/media playlist URL returns 403 due to expired tokens/signed URLs; 404 because the playlist was removed; CDN geo-blocking; rate limiting (429) under heavy segment requests.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of subhra74/xdm@1ca5a25aae (2026-09-13). Data as JSON: /api/errors/036f3a2522b1ff93. Report an issue: GitHub.

Appendix: source

Thrown at app/XDM/XDM.Core/Downloader/Adaptive/Hls/MultiSourceHLSDownloader.cs:188

                    if (status.Length == 2)
                    {
                        if (status[0] != HttpStatusCode.OK) return status[0];
                        if (status[1] != HttpStatusCode.OK) return status[1];
                        return null;
                    }
                    else
                    {
                        if (status[0] != HttpStatusCode.OK) return status[0];
                        return null;
                    }
                }

                if (!success)
                {
                    var statusCode = FindErrorStatus();
                    if (statusCode.HasValue)
                    {
                        throw new Exception($"Invalid response code: {statusCode.Value}",
                            new HttpException(statusCode.Value.ToString(), null, statusCode.Value));
                    }
                    throw new Exception("Unable to download HLS manifest");
                }

                var playlists = new Dictionary<string, HlsPlaylist>();
                if (state.Demuxed)
                {
                    playlists["video"] = HlsParser.ParseMediaSegments(results[0]!.Split('\n'), state.NonMuxedVideoPlaylistUrl.ToString());
                    playlists["audio"] = HlsParser.ParseMediaSegments(results[1]!.Split('\n'), state.NonMuxedAudioPlaylistUrl.ToString());

                    this._state.VideoContainerFormat = GuessContainerFormatFromPlaylist(playlists["video"]);
                    this._state.AudioContainerFormat = GuessContainerFormatFromPlaylist(playlists["audio"]);
                    
                    var ext = FileExtensionHelper.GuessContainerFormatFromSegmentExtension(
                            this._state.VideoContainerFormat, this._state.AudioContainerFormat);
                    TargetFileName = Path.GetFileNameWithoutExtension(TargetFileName ?? "video")
                            + ext;

View on GitHub (pinned to 1ca5a25aae)