mifi/lossless-cut · error · UnsupportedFileError

Unsupported file

Error message

Unsupported file

What it means

Thrown by readFileFfprobeMeta() when the underlying ffprobe child process fails with an execa error that has a null `code` (process not spawned/missing) but a non-null `exitCode` (ffprobe ran and exited non-zero). The original error is wrapped in an UnsupportedFileError so callers can distinguish 'ffprobe rejected this file' from genuine I/O or spawn failures. It signals ffprobe could not demux or read the container/format.

Source

Thrown at src/renderer/src/ffmpeg.ts:357

      decoded = new TextDecoder().decode(stdout);
      parsedJson = JSON.parse(decoded);
    } catch {
      console.log('ffprobe stdout:', decoded ?? stdout);
      throw new Error('ffprobe returned malformed data');
    }
    const { format, chapters = [] } = parsedJson;
    invariant(format != null);

    const streams = (parsedJson.streams ?? []).map((s) => {
      if (/DJI_[^/\\]+SRT$/.test(filePath)) {
        return { ...s, guessedType: 'dji-gps-srt' as const };
      }
      return { ...s, guessedType: undefined };
    });
    return { format, streams, chapters };
  } catch (err) {
    if (isExecaError(err) && err.code == null && err.exitCode != null) {
      throw new UnsupportedFileError('Unsupported file', { cause: err });
    }
    throw err;
  }
}

export type FileFfprobeMeta = Awaited<ReturnType<typeof readFileFfprobeMeta>>;
export type FileStream = FileFfprobeMeta['streams'][number];

async function renderThumbnail(filePath: string, timestamp: number, signal: AbortSignal) {
  const args = [
    '-ss', String(timestamp),
    '-i', filePath,
    '-vf', 'scale=-2:200',
    '-f', 'image2',
    '-vframes', '1',
    '-q:v', '10',
    '-',
  ];

View on GitHub (pinned to 3b9a59c288)

Solutions

  1. Confirm the file is a valid, complete media container using `ffprobe -i <file>` directly and read its stderr.
  2. If the file is truncated or corrupt, re-download or re-mux it (`ffmpeg -i in -c copy out`).
  3. Upgrade the bundled ffprobe/ffmpeg to a build with the required demuxer/decoder enabled.
  4. Catch UnsupportedFileError at the call site and prompt the user to pick a supported file.

Example fix

// before
const meta = await readFileFfprobeMeta(filePath);

// after
try {
  const meta = await readFileFfprobeMeta(filePath);
} catch (err) {
  if (err instanceof UnsupportedFileError) {
    throw new Error(`ffprobe could not read '${filePath}'. Is it a valid media file?`, { cause: err });
  }
  throw err;
}
Defensive patterns

Strategy: try-catch

Type guard

import { UnsupportedFileError } from '../../errors';
const isUnsupportedFileError = (err: unknown): err is UnsupportedFileError =>
  err instanceof UnsupportedFileError;

Try / catch

import { UnsupportedFileError } from '../../errors';
try {
  const meta = await readFileFfprobeMeta(filePath);
} catch (err) {
  if (err instanceof UnsupportedFileError) {
    showError(`'${filePath}' is not a supported media file.`, err.cause);
    return null;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling readFileFfprobeMeta(filePath) on a file ffprobe cannot parse (unknown codec, truncated header, DRM-protected, corrupted moov atom); a path that exists but is not a media container (e.g. a .txt renamed to .mp4); a partially-written file still being recorded.

Common situations: Damaged downloads; files with broken or missing moov/mdat atoms (MP4); encrypted/DRM media; non-media files dragged into the app; outdated ffprobe build lacking a needed demuxer; very large files where ffprobe hit an internal limit.

Related errors


AI-assisted analysis of mifi/lossless-cut@3b9a59c288 (2026-08-12). Data as JSON: /api/errors/bbdc2b442f2d2557. Report an issue: GitHub.