{"record":{"id":"861ed80dea014a89","repo":"hcengineering/platform","slug":"no-video-stream-found-in-metadata","errorCode":null,"errorMessage":"No video stream found in metadata","messagePattern":"No video stream found in metadata","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pods/preview/src/metadata/video.ts","lineNumber":104,"sourceCode":"      if (code !== 0) {\n        reject(new Error(`ffmpeg exited with code ${code}: ${error}`))\n      } else {\n        resolve()\n      }\n    })\n\n    ffmpeg.on('error', (err) => {\n      reject(new Error(`Failed to start ffmpeg: ${err.message}`))\n    })\n  })\n}\n\nfunction parseMetadata (metadata: any): VideoMetadata {\n  const streams: any[] = metadata.streams ?? []\n  const videoStream = streams.find((s) => s.codec_type === 'video')\n\n  if (videoStream === undefined) {\n    throw new Error('No video stream found in metadata')\n  }\n\n  return {\n    duration: parseFloat(metadata.format.duration),\n    width: videoStream.width,\n    height: videoStream.height\n  }\n}\n","sourceCodeStart":86,"sourceCodeEnd":113,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/pods/preview/src/metadata/video.ts#L86-L113","documentation":"parseMetadata inspects ffprobe/probe metadata and requires at least one stream with codec_type === 'video'. If the streams array is empty or contains only audio/subtitle streams, it throws 'No video stream found in metadata'.","triggerScenarios":"extractMetadata on a file whose probe output has metadata.streams missing, empty, or without any entry where codec_type === 'video' — e.g. probing an MP3 or a corrupted/unsupported container.","commonSituations":"Users upload audio files or unsupported formats renamed to a video extension; corrupted or zero-byte files; container ffprobe cannot fully parse; codecs the bundled ffmpeg build doesn't recognize.","solutions":["Validate the uploaded file is actually a video (extension + container check) before calling extractMetadata","Reject or route audio/non-media files to an appropriate handler instead of the video preview pipeline","Verify the source file is not truncated/corrupt by running ffprobe manually on it","Ensure ffmpeg/ffprobe builds support the input codec (add codecs or re-encode)"],"exampleFix":"// before\nconst meta = await extractMetadata(ctx, file)\n// after\nif (await isVideoFile(file)) {\n  const meta = await extractMetadata(ctx, file)\n} else {\n  throw new HttpError(415, 'Unsupported media type: not a video')\n}","handlingStrategy":"try-catch","validationCode":"const streams = metadata?.streams ?? []\nif (!streams.some((s: any) => s.codec_type === 'video')) {\n  // route to audio/unsupported handler instead of video preview\n}","typeGuard":"function hasVideoStream (metadata: unknown): metadata is { streams: { codec_type: 'video', width: number, height: number }[]; format: { duration: string } } {\n  const m = metadata as any\n  return m != null && Array.isArray(m.streams) && m.streams.some((s: any) => s?.codec_type === 'video')\n}","tryCatchPattern":"try {\n  const meta = await extractMetadata(ctx, file)\n} catch (err) {\n  if (err.message === 'No video stream found in metadata') {\n    return respond415('File is not a supported video')\n  }\n  throw err\n}","preventionTips":["Accept-list video MIME types/extensions on upload","Sniff file magic bytes (mkv/avi/mp4 signatures) instead of trusting extensions","Run a quick ffprobe validation before queuing the preview job","Handle audio-only uploads through a separate audio preview path"],"tags":["video","metadata","media-processing"],"backgroundTag":"no-video-stream-found","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}