mifi/lossless-cut · error · UserFacingError

No VTS vob files found in folder

Error message

No VTS vob files found in folder

What it means

Thrown by readVideoTs() when, after reading the directory and filtering for files matching ^vts_\d+_\d+\.vob$ (case-insensitive) while excluding ^vts_\d+_00\.vob$ menu VOBs, the result list is empty. The function exists to gather the playable VTS (Video Title Set) VOBs of a DVD VIDEO_TS folder, so an empty result means this is not a usable DVD structure.

Source

Thrown at src/renderer/src/util.ts:377

  if (working) {
    if (progress != null) parts.push(`${(progress * 100).toFixed(1)}%`);
    parts.push(working);
  }

  if (filePath) {
    parts.push(basename(filePath));
  }

  parts.push(isStoreBuild ? appName : `${appName} ${appVersion}`);

  document.title = parts.join(' - ');
}

export async function readVideoTs(videoTsPath: string) {
  const files = await readdir(videoTsPath);
  const relevantFiles = files.filter((file) => /^vts_\d+_\d+\.vob$/i.test(file) && !/^vts_\d+_00\.vob$/i.test(file)); // skip menu
  const ret = sortBy(relevantFiles).map((file) => join(videoTsPath, file));
  if (ret.length === 0) throw new UserFacingError(i18n.t('No VTS vob files found in folder'));
  return ret;
}

export async function readDirRecursively(dirPath: string) {
  const files = await readdir(dirPath, { recursive: true });
  const ret = (await pMap(files, async (path) => {
    if (['.DS_Store'].includes(basename(path))) return [];

    const absPath = join(dirPath, path);
    const fileStat = await lstat(absPath); // readdir also returns directories...
    if (!fileStat.isFile()) return [];

    return [absPath];
  }, { concurrency: 5 })).flat();

  if (ret.length === 0) throw new UserFacingError(i18n.t('No files found in folder'));
  return ret;
}

View on GitHub (pinned to 3b9a59c288)

Solutions

  1. Confirm the folder is a real DVD VIDEO_TS directory containing VTS_01_1.VOB, VTS_01_2.VOB, etc.
  2. Re-rip the DVD with a tool that produces the full VTS title VOBs, not just menus.
  3. Point the open-folder dialog at the exact VIDEO_TS folder, not its parent.
  4. If only a single VOB is needed, open the .vob file directly rather than via the DVD folder path.
Defensive patterns

Strategy: validation

Validate before calling

import { readdir } from 'fs/promises';
export async function hasVtsVobs(videoTsPath: string): Promise<boolean> {
  const files = await readdir(videoTsPath);
  return files.some((f) => /^vts_\d+_\d+\.vob$/i.test(f) && !/^vts_\d+_00\.vob$/i.test(f));
}
if (!(await hasVtsVobs(folder))) showError('Not a DVD VIDEO_TS folder with title VOBs.');

Try / catch

try {
  return await readVideoTs(videoTsPath);
} catch (err) {
  if (err instanceof UserFacingError && /No VTS vob files/.test(err.message)) {
    showError('The selected folder has no DVD title VOBs.');
    return [];
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling readVideoTs(dir) on a folder that contains no VTS_*_*.VOB files; pointing at a VIDEO_TS folder that only has menu VOBs (VTS_xx_00.VOB); selecting a regular folder that merely happens to be named VIDEO_TS but holds no DVD content.

Common situations: User selects the wrong folder (the parent of VIDEO_TS, or a BUP/IFO-only folder); an incompletely ripped DVD missing the title VOBs; a folder containing only the menu/title set metadata; a non-DVD folder passed to the DVD-open path.

Related errors


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