immich-app/immich · error · BadRequestException

Real-time transcoding is not enabled

Error message

Real-time transcoding is not enabled

What it means

HLS video streaming in Immich uses real-time transcoding, which must be explicitly enabled in server configuration (System Settings -> Video Encoding -> Transcoding -> 'accelerate transcoding for real-time playback' / ffmpeg.realtime.enabled). getMainPlaylist refuses to start a session when this is off because the whole HLS pipeline assumes the realtime segmenter. It returns 400 BadRequestException.

Source

Thrown at server/src/services/hls.service.ts:51

    }
  }

  @OnEvent({ name: 'HlsSessionEnd', server: true, workers: [ImmichWorker.Api] })
  onSessionEnd({ sessionId }: ArgOf<'HlsSessionEnd'>) {
    this.sessions.delete(sessionId);
    this.pendingSegments.rejectByPrefix(`${sessionId}:`, 'Session ended');
  }

  @OnEvent({ name: 'HlsSegmentResult', server: true, workers: [ImmichWorker.Api] })
  onSegmentResult(event: ArgOf<'HlsSegmentResult'>) {
    this.pendingSegments.complete(this.getSegmentKey(event), event);
  }

  async getMainPlaylist(auth: AuthDto, assetId: string) {
    await this.requireAccess({ auth, permission: Permission.AssetView, ids: [assetId] });
    const { ffmpeg } = await this.getConfig({ withCache: true });
    if (!ffmpeg.realtime.enabled) {
      throw new BadRequestException('Real-time transcoding is not enabled');
    }

    const asset = await this.videoStreamRepository.getForMainPlaylist(assetId);
    if (!asset) {
      throw new NotFoundException('Asset metadata is not yet ready for streaming');
    }

    // Sharing the sessionId allows only one microservices worker to successfully insert to the session table.
    // The microservices worker that creates a session owns the transcoding lifecycle for it.
    const sessionId = this.cryptoRepository.randomUUID();
    this.websocketRepository.serverSend('HlsSessionRequest', { sessionId, assetId, ownerId: auth.user.id });
    await this.pendingSessions.wait(sessionId);
    this.trackSession(sessionId);

    return this.generateMainPlaylist(sessionId, ffmpeg, asset);
  }

  async getMediaPlaylist(auth: AuthDto, assetId: string, sessionId: string, variantIndex: number, position?: number) {

View on GitHub (pinned to 199723261c)

Solutions

  1. In the Admin UI open Settings -> Video Encoding -> enable real-time transcoding (set ffmpeg.realtime.enabled = true).
  2. Alternatively set it via the system-config API/PATCH /system-config with notifications...ffmpeg.realtime.enabled true.
  3. Ensure the machine has enough CPU/GPU for realtime transcoding before enabling.
  4. Re-request the playlist once the config is saved (it is read withCache, so a reload may be needed).

Example fix

// before: config value
// ffmpeg.realtime.enabled = false
// after (PATCH /system-config)
patch['ffmpeg.realtime.enabled'] = true;
Defensive patterns

Strategy: validation

Validate before calling

const config = await api.systemConfigApi.getConfig();
if (!config.ffmpeg.realtime.enabled) {
  throw new Error('Real-time transcoding is disabled - enable it to use HLS playback');
}

Type guard

const isRealtimeEnabled = (cfg: { ffmpeg: { realtime: { enabled: boolean } } }) =>
  cfg.ffmpeg.realtime.enabled === true;

Try / catch

try {
  await api.hlsApi.getMainPlaylist(auth, assetId);
} catch (e) {
  if (e.status === 400 && /Real-time transcoding is not enabled/.test(e.message)) {
    promptEnableRealtimeTranscoding();
  } else throw e;
}

Prevention

When it happens

Trigger: Client requests the main HLS playlist for an asset (GET /assets/{id}/video/playlists/main.m3u8) while system config ffmpeg.realtime.enabled is false (the default).

Common situations: Fresh Immich install where realtime transcoding was never turned on; admin disabled it to save CPU; config reset after a restore.

Related errors


AI-assisted analysis of immich-app/immich@199723261c (2026-08-12). Data as JSON: /api/errors/78c1c8bca63844ea. Report an issue: GitHub.