immich-app/immich · error · NotFoundException
No supported variants for this video
Error message
No supported variants for this video
What it means
generateMainPlaylist builds one EXT-X-STREAM-INF line per transcoding resolution the asset supports; if none could be added (lines.length === 4 means only the header lines remain), it throws 404 NotFoundException 'No supported variants for this video'. This happens when the asset's video codec/stream is not compatible with any configured output variant, or the codec string/resolution computation rejected every option.
Source
Thrown at server/src/services/hls.service.ts:149
const targetResolution = Math.max(sourceResolution, HLS_VARIANTS[0].resolution);
const lines = ['#EXTM3U', `#EXT-X-VERSION:${HLS_VERSION}`, '#EXT-X-INDEPENDENT-SEGMENTS'];
const { videoCodecs, resolutions } = ffmpeg.realtime;
for (let i = 0; i < HLS_VARIANTS.length; i++) {
const { resolution, bitrate, codec } = HLS_VARIANTS[i];
if (resolution > targetResolution || !videoCodecs.includes(codec) || !resolutions.includes(resolution)) {
continue;
}
const { width, height } = getOutputSize(asset.videoStream, resolution);
const codecString = getCodecString(codec, width, height, fps);
lines.push(
`#EXT-X-STREAM-INF:BANDWIDTH=${Math.round(bitrate * 1.35)},RESOLUTION=${width}x${height},CODECS="${codecString},mp4a.40.2",VIDEO-RANGE=SDR,FRAME-RATE=${roundedFps}`,
`${sessionId}/${i}/playlist.m3u8`,
);
}
lines.push('');
if (lines.length === 4) {
throw new NotFoundException('No supported variants for this video');
}
return lines.join('\n');
}
private getSegmentation({ videoStream, packets }: AssetWithStreamInfo): Segmentation {
const fps = (packets.packetCount * videoStream.timeBase) / packets.totalDuration;
const framesPerSegment = Math.ceil(HLS_SEGMENT_DURATION * fps);
const segmentCount = Math.ceil(packets.outputFrames / framesPerSegment);
return { fps, framesPerSegment, segmentCount, segmentDuration: framesPerSegment / fps };
}
private positionToSegmentIndex({ segmentDuration, segmentCount }: Segmentation, position: number) {
return Math.min(Math.max(Math.floor(position / segmentDuration), 0), segmentCount - 1);
}
private generateMediaPlaylist({ packets }: AssetWithStreamInfo, segmentation: Segmentation) {
const { fps, framesPerSegment, segmentCount, segmentDuration: fullSegmentDuration } = segmentation;View on GitHub (pinned to 199723261c)
Solutions
- Review System Settings -> Video Encoding and ensure at least one targetVideoCodec is enabled that the source can be transcoded to (commonly h264).
- Confirm a transcode target resolution is enabled (CONVERTED_VIDEO_FORMATS / desired resolutions).
- Check the asset's actual codec via the asset metadata and install/enable the decoder (e.g. enable HEVC support in ffmpeg).
- As a last resort, transcode the source file externally and re-upload it in a supported format.
Defensive patterns
Strategy: try-catch
Validate before calling
// check the asset's codec is supported by configured transcode targets before offering HLS
const cfg = await api.systemConfigApi.getConfig();
const supportedCodecs = cfg.ffmpeg.targetVideoCodec; // e.g. ['h264','hevc']
const asset = await api.assetApi.get(assetId);
if (!supportedCodecs.includes(asset.imageCodec /* or videoCodec */)) {
warnUnsupportedCodec(asset);
} Type guard
const hasSupportedVariant = (asset: { videoCodec?: string }, targets: string[]) =>
!!asset.videoCodec && targets.includes(asset.videoCodec); Try / catch
try {
await api.hlsApi.getMainPlaylist(auth, assetId);
} catch (e) {
if (e.status === 404 && /No supported variants/.test(e.message)) {
showFallback('Direct download only - no streaming variants available for this codec');
} else throw e;
} Prevention
- Enable at least h264 as a target transcode codec.
- Keep ffmpeg decoders broad enough for source codecs (e.g. HEVC, VP9).
- Offer a direct-download fallback in the player for unsupported sources.
When it happens
Trigger: getMainPlaylist proceeds, asset metadata exists, but every variant was skipped in the loop (e.g. continue due to codec/targetVideoCodec mismatch, an exotic codec like HEVC with no transcode target enabled, or all resolutions higher/lower than configured). Result: no stream-INF lines.
Common situations: Video in a codec the configured transcode stack cannot decode; targetVideoCodec misconfigured; all transcode resolutions disabled; very unusual container/codec combo.
Related errors
- Real-time transcoding is not enabled
- Asset metadata is not yet ready for streaming
- Asset not found or metadata not yet ready for streaming
- Session not found
- Asset not found or asset is not a video
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/87abadcfd0183659.
Report an issue: GitHub.