{"record":{"id":"78c1c8bca63844ea","repo":"immich-app/immich","slug":"real-time-transcoding-is-not-enabled","errorCode":null,"errorMessage":"Real-time transcoding is not enabled","messagePattern":"Real-time transcoding is not enabled","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"server/src/services/hls.service.ts","lineNumber":51,"sourceCode":"    }\n  }\n\n  @OnEvent({ name: 'HlsSessionEnd', server: true, workers: [ImmichWorker.Api] })\n  onSessionEnd({ sessionId }: ArgOf<'HlsSessionEnd'>) {\n    this.sessions.delete(sessionId);\n    this.pendingSegments.rejectByPrefix(`${sessionId}:`, 'Session ended');\n  }\n\n  @OnEvent({ name: 'HlsSegmentResult', server: true, workers: [ImmichWorker.Api] })\n  onSegmentResult(event: ArgOf<'HlsSegmentResult'>) {\n    this.pendingSegments.complete(this.getSegmentKey(event), event);\n  }\n\n  async getMainPlaylist(auth: AuthDto, assetId: string) {\n    await this.requireAccess({ auth, permission: Permission.AssetView, ids: [assetId] });\n    const { ffmpeg } = await this.getConfig({ withCache: true });\n    if (!ffmpeg.realtime.enabled) {\n      throw new BadRequestException('Real-time transcoding is not enabled');\n    }\n\n    const asset = await this.videoStreamRepository.getForMainPlaylist(assetId);\n    if (!asset) {\n      throw new NotFoundException('Asset metadata is not yet ready for streaming');\n    }\n\n    // Sharing the sessionId allows only one microservices worker to successfully insert to the session table.\n    // The microservices worker that creates a session owns the transcoding lifecycle for it.\n    const sessionId = this.cryptoRepository.randomUUID();\n    this.websocketRepository.serverSend('HlsSessionRequest', { sessionId, assetId, ownerId: auth.user.id });\n    await this.pendingSessions.wait(sessionId);\n    this.trackSession(sessionId);\n\n    return this.generateMainPlaylist(sessionId, ffmpeg, asset);\n  }\n\n  async getMediaPlaylist(auth: AuthDto, assetId: string, sessionId: string, variantIndex: number, position?: number) {","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/immich-app/immich/blob/199723261c6ffa897fec8ccdaea6359e39c37cc3/server/src/services/hls.service.ts#L33-L69","documentation":"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.","triggerScenarios":"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).","commonSituations":"Fresh Immich install where realtime transcoding was never turned on; admin disabled it to save CPU; config reset after a restore.","solutions":["In the Admin UI open Settings -> Video Encoding -> enable real-time transcoding (set ffmpeg.realtime.enabled = true).","Alternatively set it via the system-config API/PATCH /system-config with notifications...ffmpeg.realtime.enabled true.","Ensure the machine has enough CPU/GPU for realtime transcoding before enabling.","Re-request the playlist once the config is saved (it is read withCache, so a reload may be needed)."],"exampleFix":"// before: config value\n// ffmpeg.realtime.enabled = false\n// after (PATCH /system-config)\npatch['ffmpeg.realtime.enabled'] = true;","handlingStrategy":"validation","validationCode":"const config = await api.systemConfigApi.getConfig();\nif (!config.ffmpeg.realtime.enabled) {\n  throw new Error('Real-time transcoding is disabled - enable it to use HLS playback');\n}","typeGuard":"const isRealtimeEnabled = (cfg: { ffmpeg: { realtime: { enabled: boolean } } }) =>\n  cfg.ffmpeg.realtime.enabled === true;","tryCatchPattern":"try {\n  await api.hlsApi.getMainPlaylist(auth, assetId);\n} catch (e) {\n  if (e.status === 400 && /Real-time transcoding is not enabled/.test(e.message)) {\n    promptEnableRealtimeTranscoding();\n  } else throw e;\n}","preventionTips":["Surface realtime transcoding as an admin setup step during initial deployment.","Have the client check the config flag before offering HLS playback.","Document CPU/GPU requirements before enabling realtime."],"tags":["config","video","hls","ffmpeg","transcoding","bad-request","immich","nestjs"],"backgroundTag":null,"analyzedSha":"199723261c6ffa897fec8ccdaea6359e39c37cc3","analyzedAt":"2026-08-12T04:54:27.085Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}