jackwener/OpenCLI · error · CommandExecutionError

Browser reported a completed download but the file is missin

Error message

Browser reported a completed download but the file is missing: ${sourcePath}

What it means

A CommandExecutionError raised when the Browser Bridge reports a completed download with a filename, but fs.stat on the resolved path finds no regular file or a zero-byte file. This guards against trusting the bridge's success report when the file was moved, deleted, or never actually flushed to disk.

Source

Thrown at clis/midjourney/utils.js:765

    const button = [...document.querySelectorAll('button[role="menuitem"],button')]
      .find((node) => node.textContent?.trim() === label && node.getBoundingClientRect().width > 0);
    if (!button) return false;
    button.setAttribute('data-opencli-video-download', '1');
    return true;
  }, config.label));
  if (!marked) throw new CommandExecutionError(`Midjourney did not expose "${config.label}" for video ${jobId}`);
  await page.click('[data-opencli-video-download="1"]');
  if (typeof page.waitForDownload !== 'function') {
    throw new CommandExecutionError('Browser Bridge download lifecycle support is required for social video/GIF export');
  }
  const downloaded = await page.waitForDownload(jobId, 60_000);
  if (!downloaded?.downloaded || downloaded.state !== 'complete' || !downloaded.filename) {
    throw new CommandExecutionError(`Midjourney ${kind} download did not complete: ${downloaded?.error || downloaded?.state || 'unknown'}`);
  }
  const sourcePath = path.resolve(String(downloaded.filename));
  const sourceStat = await fs.stat(sourcePath).catch(() => null);
  if (!sourceStat?.isFile() || sourceStat.size <= 0) {
    throw new CommandExecutionError(`Browser reported a completed download but the file is missing: ${sourcePath}`);
  }
  const handle = await fs.open(sourcePath, 'r');
  let actualMime;
  try {
    const header = Buffer.alloc(16);
    const { bytesRead } = await handle.read(header, 0, header.length, 0);
    actualMime = sniffMediaMime(header.subarray(0, bytesRead));
  } finally {
    await handle.close();
  }
  if (actualMime !== config.mime) {
    throw new CommandExecutionError(
      `Midjourney ${kind} returned invalid media bytes; expected ${config.mime}, detected ${actualMime || 'unknown'}`,
    );
  }
  if (downloaded.mime && downloaded.mime !== actualMime) {
    log.warn(`Browser Bridge reported ${downloaded.mime} for ${sourcePath}; detected ${actualMime} from file bytes`);
  }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Add a small delay/retry loop around fs.stat to allow the file to finish flushing
  2. If using a snap/flatpak-packaged browser, resolve the downloaded path against the browser's real download directory rather than path.resolve
  3. Check antivirus quarantine logs and exclude the download directory
  4. Verify the bridge returns an absolute filename; adapt if it reports only a basename
  5. Re-run the download; a zero-byte file usually indicates a transient failure

Example fix

// before
const sourceStat = await fs.stat(sourcePath).catch(() => null);
if (!sourceStat?.isFile() || sourceStat.size <= 0) throw ...;
// after
let sourceStat = null;
for (let i = 0; i < 5 && !sourceStat; i++) {
  await new Promise((r) => setTimeout(r, 500));
  sourceStat = await fs.stat(sourcePath).catch(() => null);
}
if (!sourceStat?.isFile() || sourceStat.size <= 0) throw ...;
Defensive patterns

Strategy: retry

Validate before calling

const stat = await fs.promises.stat(bridgeDownloadDir).catch(() => null);
if (!stat?.isDirectory()) throw new Error('Browser download directory is not accessible from this process');

Type guard

async function downloadedFileReady(p) {
  const s = await fs.promises.stat(p).catch(() => null);
  return Boolean(s?.isFile() && s.size > 0);
}

Try / catch

try {
  await downloadRenderedVideo(page, jobId, i, kind, outDir);
} catch (err) {
  if (err.message.includes('file is missing')) {
    console.error(`Browser download path unreachable: ${err.message}. Check sandbox (snap/flatpak) path mapping.`);
  } else throw err;
}

Prevention

When it happens

Trigger: fs.stat(sourcePath) rejects (path resolves to null) or the stat shows size <= 0 immediately after waitForDownload reported state 'complete'.

Common situations: The browser's download temp file was still being finalized when stat ran (race); the browser downloaded to a sandboxed/virtual filesystem (snap/flatpak Chromium) whose path differs from the host path; antivirus quarantined the file; the bridge reported a relative or stale filename.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/3411fdc57d53fc83. Report an issue: GitHub.