immich-app/immich · error · NotFoundException
Asset not found or metadata not yet ready for streaming
Error message
Asset not found or metadata not yet ready for streaming
What it means
Guard when opening an HLS stream: the asset's transcode metadata (video stream info, segmentation) has not been generated yet by the background metadata pipeline, or the asset id does not exist, so playback cannot start. Raised in getMediaPlaylist as a 404 before requesting a transcode session from the microservices worker. Fires for brand-new uploads whose metadata is still processing or stale/deleted asset ids.
Solutions
- Poll/retry after a short delay until asset metadata extraction completes
- Verify the assetId exists before requesting the playlist
- Show the user a 'video is still processing' state instead of the player
- Check that the metadata/transcode worker service is running and healthy
Defensive patterns
Strategy: retry
When it happens
Trigger: Thrown at server/src/services/hls.service.ts:74 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/a8ec1ca241996ce4.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/hls.service.ts:74
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) {
await this.requireAccess({ auth, permission: Permission.AssetView, ids: [assetId] });
const asset = await this.videoStreamRepository.getForMediaPlaylist(assetId, sessionId);
if (!asset) {
throw new NotFoundException('Asset not found or metadata not yet ready for streaming');
}
const segmentation = this.getSegmentation(asset);
const hintedSegment = position === undefined ? undefined : this.positionToSegmentIndex(segmentation, position);
this.prewarmVariant(assetId, sessionId, variantIndex, hintedSegment);
return this.generateMediaPlaylist(asset, segmentation);
}
async getSegment(
auth: AuthDto,
assetId: string,
sessionId: string,
variantIndex: number,
filename: string,
initSegment?: number,
) {
await this.requireAccess({ auth, permission: Permission.AssetView, ids: [assetId] });View on GitHub (pinned to e55ac299a4)