immich-app/immich · warning

Skipped transcoding for asset

Error message

Skipped transcoding for asset ${asset.id}: no video dimensions

What it means

After confirming stream/format metadata exist, transcoding still requires nonzero video dimensions (height and width) to compute scaling and target bitrate. A video stream without dimensions is logged with this warning and the job returns JobStatus.Failed.

Solutions

  1. Re-run metadata extraction for the asset to repopulate height/width
  2. Verify the file with ffprobe/ffmpeg -i; replace or re-upload if the video is corrupt
  3. Upgrade ffmpeg/ffprobe if the codec's dimensions cannot be probed
  4. Check DB: SELECT width, height FROM video_stream WHERE asset_id = '<id>' to confirm the bad row

Example fix

// before
if (!videoStream.height || !videoStream.width) { this.logger.warn(`Skipped transcoding for asset ${asset.id}: no video dimensions`); return JobStatus.Failed; }
// after
if (!videoStream.height || !videoStream.width) { this.logger.warn(`Skipped transcoding for asset ${asset.id}: no video dimensions`); await this.jobRepository.queue({ name: JobName.VideoMetadata, data: { id: asset.id } }); return JobStatus.Failed; }
Defensive patterns

Strategy: retry

Validate before calling

if (videoStream && (!videoStream.height || !videoStream.width)) {
  await jobRepository.queue({ name: JobName.VideoMetadata, data: { id: asset.id } }); // re-extract dimensions
}

Try / catch

if (!videoStream.height || !videoStream.width) {
  this.logger.warn(`Skipped transcoding for asset ${asset.id}: no video dimensions`);
  return JobStatus.Failed; // then re-run metadata extraction and retry
}

Prevention

When it happens

Trigger: handleVideoConversion reads a videoStream row where height or width is 0/null — typically from a partial or failed ffprobe extraction, or a codec ffprobe could not measure (e.g. exotic codecs, rotated streams with missing side data).

Common situations: ffprobe version issues producing empty dimension fields; corrupted or truncated video files; unusual codecs (e.g. some AV1/ProRes variants) on older ffmpeg builds; rows written before dimensions were extracted.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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

Appendix: source

Thrown at server/src/services/media.service.ts:565

  @OnJob({ name: JobName.AssetEncodeVideo, queue: QueueName.VideoConversion })
  async handleVideoConversion({ id }: JobOf<JobName.AssetEncodeVideo>): Promise<JobStatus> {
    const asset = await this.assetJobRepository.getForVideoConversion(id);
    if (!asset) {
      return JobStatus.Failed;
    }

    const input = asset.originalPath;
    const output = StorageCore.getEncodedVideoPath(asset);
    this.storageCore.ensureFolders(output);

    const { videoStream, format } = asset;
    const audioStream = asset.audioStream ?? undefined;
    if (!videoStream || !format) {
      this.logger.warn(`Skipped transcoding for asset ${asset.id}: missing metadata; re-run extraction first`);
      return JobStatus.Failed;
    }
    if (!videoStream.height || !videoStream.width) {
      this.logger.warn(`Skipped transcoding for asset ${asset.id}: no video dimensions`);
      return JobStatus.Failed;
    }

    let { ffmpeg } = await this.getConfig({ withCache: true });
    const target = this.getTranscodeTarget(ffmpeg, videoStream, audioStream);
    if (target === TranscodeTarget.None && !this.isRemuxRequired(ffmpeg, format)) {
      const encodedVideo = getAssetFile(asset.files, AssetFileType.EncodedVideo, { isEdited: false });
      if (encodedVideo) {
        this.logger.log(`Transcoded video exists for asset ${asset.id}, but is no longer required. Deleting...`);
        await this.jobRepository.queue({ name: JobName.FileDelete, data: { files: [encodedVideo.path] } });
        await this.assetRepository.deleteFiles([encodedVideo]);
      } else {
        this.logger.verbose(`Asset ${asset.id} does not require transcoding based on current policy, skipping`);
      }

      return JobStatus.Skipped;
    }

View on GitHub (pinned to e55ac299a4)