jackwener/OpenCLI · error · CommandExecutionError

Browser Bridge download lifecycle support is required for so

Error message

Browser Bridge download lifecycle support is required for social video/GIF export

What it means

A CommandExecutionError raised when the page object lacks a waitForDownload function, meaning the connected Browser Bridge does not implement the download lifecycle API. The social/GIF export flow relies on the bridge to report when a browser-initiated download completes; without that hook it cannot reliably capture the file.

Source

Thrown at clis/midjourney/utils.js:756

  const existing = await existingMedia(filePath, force, config.mime);
  if (existing) return { index, kind, filePath, bytes: existing.size, url: null, mime: config.mime, cached: true };

  await page.goto(jobUrl(jobId, index));
  await page.wait({ selector: 'video[src]', timeout: 20 });
  await page.click('button[title="Options"]');
  await page.wait(0.3);
  const marked = unwrapEvaluateResult(await page.evaluate((label) => {
    document.querySelectorAll('[data-opencli-video-download]').forEach((node) => node.removeAttribute('data-opencli-video-download'));
    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();

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Upgrade the Browser Bridge client/extension to a version that implements waitForDownload(jobId, timeoutMs)
  2. Ensure the CLI connects through the official bridge-managed page object rather than a raw Playwright/Puppeteer page
  3. Pin matching versions of the CLI and bridge packages in your environment
  4. If you maintain a custom bridge, implement waitForDownload returning { downloaded, state, filename, mime }

Example fix

// before
const page = await playwright.chromium.launch().newPage();
await downloadRenderedVideo(page, jobId, 0, 'gif', outDir);
// after
const page = await bridge.connect({ browser: 'chromium' }); // bridge page implements waitForDownload
await downloadRenderedVideo(page, jobId, 0, 'gif', outDir);
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof page?.waitForDownload !== 'function') {
  throw new Error('Browser Bridge lacks waitForDownload — upgrade the bridge client before exporting social video/GIF');
}
await downloadRenderedVideo(page, jobId, i, kind, outDir);

Type guard

function supportsDownloadLifecycle(page) {
  return typeof page?.waitForDownload === 'function';
}

Try / catch

try {
  await downloadRenderedVideo(page, jobId, i, kind, outDir);
} catch (err) {
  if (err.message.includes('download lifecycle support')) {
    console.error('Upgrade your Browser Bridge: npm i -g @opencli/browser-bridge@latest');
  } else throw err;
}

Prevention

When it happens

Trigger: downloadRenderedVideo clicks the marked download button, then checks typeof page.waitForDownload === 'function' and it is undefined — the bridge client is an older version or a plain Playwright/Puppeteer page without the extension.

Common situations: Running an outdated opencli browser-bridge client against a newer CLI (or vice versa); using a self-built bridge that never implemented waitForDownload; pointing the CLI at a browser session not managed by the bridge.

Related errors


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