immich-app/immich · error · Error

Codec ' ' does not support HLS codec strings

Error message

Codec '${codec}' does not support HLS codec strings

What it means

getCodecString builds the HLS CODECS attribute string for a target video codec, but only H.264, HEVC, and AV1 have defined codec-string builders. Other codecs (e.g. VP9 or unknown values) cannot be represented in this HLS string, so the default branch throws.

Solutions

  1. Switch targetVideoCodec to H.264, HEVC, or AV1 for HLS transcoding
  2. If VP9 output is required, use a non-HLS delivery path (e.g. MP4/WebM progressive)
  3. Upgrade Immich if a newer version added codec-string support for your codec

Example fix

// before
config.targetVideoCodec = VideoCodec.Vp9;
const str = getCodecString(config.targetVideoCodec, w, h, fps);
// after
config.targetVideoCodec = VideoCodec.Hevc;
const str = getCodecString(config.targetVideoCodec, w, h, fps);
Defensive patterns

Strategy: validation

Validate before calling

const HLS_CODECS = ['h264', 'hevc', 'av1'];
if (!HLS_CODECS.includes(config.targetVideoCodec)) {
  throw new Error(`${config.targetVideoCodec} cannot be used for HLS; pick h264/hevc/av1`);
}

Type guard

const supportsHls = (c) => c === 'h264' || c === 'hevc' || c === 'av1';

Try / catch

try {
  const s = getCodecString(config.targetVideoCodec, w, h, fps);
} catch (e) {
  if (/does not support HLS codec strings/.test(e.message)) {
    // fall back to a supported codec or non-HLS delivery
  }
}

Prevention

When it happens

Trigger: Transcoding configured with targetVideoCodec set to a codec without an HLS codec-string case (e.g. VideoCodec.Vp9) while generating HLS output.

Common situations: Choosing VP9 as the target codec expecting it to work everywhere; config from experimental versions; enum value drift after codec additions/removals.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15). Data as JSON: /api/errors/df3c7d1564da3bd4. Report an issue: GitHub.

Appendix: source

Thrown at server/src/utils/media.ts:64

const pickLevel = (levels: CodecLevel[], frame: number, rate: number) =>
  levels.find((level) => frame <= level.maxFrame && rate <= level.maxRate) ?? levels.at(-1)!;

export const getCodecString = (codec: VideoCodec, width: number, height: number, fps: number): string => {
  switch (codec) {
    case VideoCodec.H264: {
      const macroblocks = Math.ceil(width / 16) * Math.ceil(height / 16);
      return `avc1.6400${pickLevel(H264_LEVELS, macroblocks, macroblocks * fps).token}`;
    }
    case VideoCodec.Hevc: {
      const samples = width * height;
      return `hvc1.1.6.${pickLevel(HEVC_LEVELS, samples, samples * fps).token}.B0`;
    }
    case VideoCodec.Av1: {
      const samples = width * height;
      return `av01.0.${pickLevel(AV1_LEVELS, samples, samples * fps).token}.08`;
    }
    default: {
      throw new Error(`Codec '${codec}' does not support HLS codec strings`);
    }
  }
};

export class BaseConfig implements VideoCodecSWConfig {
  readonly presets = ['veryslow', 'slower', 'slow', 'medium', 'fast', 'faster', 'veryfast', 'superfast', 'ultrafast'];
  protected constructor(
    protected config: ConfigFFmpegDto,
    protected tune: VideoTuning = { strictGop: false, lowLatency: false },
  ) {}

  static create(config: ConfigFFmpegDto, interfaces: VideoInterfaces, tune?: VideoTuning) {
    if (config.accel === TranscodeHardwareAcceleration.Disabled) {
      return BaseConfig.getSWCodecConfig(config, tune);
    }
    return BaseConfig.getHWCodecConfig(config, interfaces, tune);
  }

View on GitHub (pinned to e55ac299a4)