AlistGo/alist · error
sub playlist not found in master m3u8
Error message
sub playlist not found in master m3u8
What it means
While resolving an m3u8 video link, the driver parsed the master playlist (looking for a #EXT-X-STREAM-INF line followed by a URI, then falling back to the last non-comment, non-empty line) and found no candidate sub-playlist path at all. It cannot proceed to fetch the actual media segments.
Source
Thrown at drivers/139/util.go:1598
if i+1 < len(lines) {
subRelPath = strings.TrimSpace(lines[i+1])
if strings.Contains(line, "1920x1080") {
break
}
}
}
}
if subRelPath == "" {
for i := len(lines) - 1; i >= 0; i-- {
line := strings.TrimSpace(lines[i])
if line != "" && !strings.HasPrefix(line, "#") {
subRelPath = line
break
}
}
}
if subRelPath == "" {
return "", fmt.Errorf("sub playlist not found in master m3u8")
}
// 3. Get sub-playlist content
base, _ := url.Parse(masterURL)
ref, _ := url.Parse(subRelPath)
subURL := base.ResolveReference(ref).String()
resp, err = client.R().SetHeaders(headers).Get(subURL)
if err != nil {
return "", err
}
subContent := resp.String()
// 4. Resolve relative TS paths to absolute URLs
subBase, _ := url.Parse(subURL)
subLines := strings.Split(subContent, "\n")
var finalLines []string
for _, line := range subLines {View on GitHub (pinned to 843d9dc814)
Solutions
- Retry after a short delay — transcode-not-ready playlists frequently become valid once processing finishes
- Dump the master m3u8 content (log masterURL and body) to confirm whether it is a valid master playlist, a media playlist, or an error page
- If it is already a media playlist (contains #EXTINF segments but no variants), resolve segment URLs directly instead of recursing; update OpenList or patch locally
- Check the token/Referer headers still match what the CDN expects
Example fix
// before
if subRelPath == "" {
return "", fmt.Errorf("sub playlist not found in master m3u8")
}
// after (treat as media playlist when segments exist)
if subRelPath == "" {
if strings.Contains(masterContent, "#EXTINF") {
return masterURL, nil // already a media playlist
}
return "", fmt.Errorf("sub playlist not found in master m3u8")
} Defensive patterns
Strategy: fallback
Validate before calling
// Validate the master playlist before searching for variants
lines := strings.Split(masterContent, "\n")
if !containsTag(lines, "#EXTM3U") {
return fmt.Errorf("not a valid m3u8 playlist: %q", truncate(masterContent, 64))
} Type guard
func isMasterPlaylist(content string) bool {
return strings.Contains(content, "#EXT-X-STREAM-INF")
} Try / catch
// Fall back to treating the URL as a direct media playlist
url, err := resolveSubPlaylist(master)
if err != nil && strings.Contains(err.Error(), "sub playlist not found") {
if strings.Contains(master.content, "#EXTINF") {
return masterURL, nil
}
return "", err
} Prevention
- Retry m3u8 fetches shortly after upload — transcoding playlists appear late
- Always check for #EXTM3U before parsing to distinguish playlists from error pages
- Cache resolved sub-playlist URLs briefly to avoid re-fetching masters
When it happens
Trigger: getLink for a video returns an m3u8 whose content is only tags/comments (e.g. a bare #EXTM3U, an error playlist, or a media playlist already), or the body is HTML that happens to pass earlier checks, leaving subRelPath empty.
Common situations: Upstream CDN serving an error/empty playlist when the video transcode is not ready, token-expired playlists, or format changes in the 139 video preview API.
Related errors
- not get file info
- no valid path mapping found
- wukong video upload missing vid in commit response
- expire invalid
- that's not even a token
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/2a2ca33e726d3c1f.
Report an issue: GitHub.