{"record":{"id":"fbdb1febdd351e3a","repo":"jackwener/OpenCLI","slug":"midjourney-did-not-expose-config-label-for-vi","errorCode":null,"errorMessage":"Midjourney did not expose \"${config.label}\" for video ${jobId}","messagePattern":"Midjourney did not expose \"(.+?)\" for video (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/midjourney/utils.js","lineNumber":753,"sourceCode":"  if (!config) throw new ArgumentError('Rendered video kind must be video-social or gif');\n  await fs.mkdir(outputDir, { recursive: true });\n  const filePath = path.join(outputDir, `${jobId}_${index + 1}_${kind.replace('video-', '')}${config.extension}`);\n  const existing = await existingMedia(filePath, force, config.mime);\n  if (existing) return { index, kind, filePath, bytes: existing.size, url: null, mime: config.mime, cached: true };\n\n  await page.goto(jobUrl(jobId, index));\n  await page.wait({ selector: 'video[src]', timeout: 20 });\n  await page.click('button[title=\"Options\"]');\n  await page.wait(0.3);\n  const marked = unwrapEvaluateResult(await page.evaluate((label) => {\n    document.querySelectorAll('[data-opencli-video-download]').forEach((node) => node.removeAttribute('data-opencli-video-download'));\n    const button = [...document.querySelectorAll('button[role=\"menuitem\"],button')]\n      .find((node) => node.textContent?.trim() === label && node.getBoundingClientRect().width > 0);\n    if (!button) return false;\n    button.setAttribute('data-opencli-video-download', '1');\n    return true;\n  }, config.label));\n  if (!marked) throw new CommandExecutionError(`Midjourney did not expose \"${config.label}\" for video ${jobId}`);\n  await page.click('[data-opencli-video-download=\"1\"]');\n  if (typeof page.waitForDownload !== 'function') {\n    throw new CommandExecutionError('Browser Bridge download lifecycle support is required for social video/GIF export');\n  }\n  const downloaded = await page.waitForDownload(jobId, 60_000);\n  if (!downloaded?.downloaded || downloaded.state !== 'complete' || !downloaded.filename) {\n    throw new CommandExecutionError(`Midjourney ${kind} download did not complete: ${downloaded?.error || downloaded?.state || 'unknown'}`);\n  }\n  const sourcePath = path.resolve(String(downloaded.filename));\n  const sourceStat = await fs.stat(sourcePath).catch(() => null);\n  if (!sourceStat?.isFile() || sourceStat.size <= 0) {\n    throw new CommandExecutionError(`Browser reported a completed download but the file is missing: ${sourcePath}`);\n  }\n  const handle = await fs.open(sourcePath, 'r');\n  let actualMime;\n  try {\n    const header = Buffer.alloc(16);\n    const { bytesRead } = await handle.read(header, 0, header.length, 0);","sourceCodeStart":735,"sourceCodeEnd":771,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/midjourney/utils.js#L735-L771","documentation":"A CommandExecutionError thrown when the injected in-page script cannot find a visible button whose trimmed text exactly equals the expected menu label (e.g. 'Download for Social' or 'Download as GIF') on the Midjourney video page. The library marks the matching menu item before clicking it, so absence of the button means Midjourney's UI does not offer that export for this video.","triggerScenarios":"page.evaluate marking script runs on the job page and returns false because no visible button matches config.label — Midjourney's dropdown has different text, the menu wasn't opened, or the video has no such export option.","commonSituations":"Midjourney shipped a UI update renaming or relocating the download menu items; the job is still processing or is a video type without social/GIF export; the page didn't finish loading before evaluate ran; regional/localized UI text differing from English labels.","solutions":["Wait for the video page and its action menu to fully render before calling downloadRenderedVideo","Verify the current Midjourney UI button text and update the label in the config map ('Download for Social' / 'Download as GIF')","Confirm this video job actually supports social/GIF export (some video variants do not)","Update your browser session/region so the UI renders the expected English labels","Add a retry that opens the dropdown/menu first, then re-runs the marking script"],"exampleFix":"// before\nawait page.goto(jobUrl(jobId, index));\nconst marked = await page.evaluate(markScript, config.label);\n// after\nawait page.goto(jobUrl(jobId, index));\nawait page.waitForSelector('button[role=\"menuitem\"], button', { timeout: 30_000 });\nconst marked = await page.evaluate(markScript, config.label);\nif (!marked) throw new CommandExecutionError(`Midjourney did not expose \"${config.label}\" for video ${jobId}`);","handlingStrategy":"retry","validationCode":"await page.goto(jobUrl(jobId, index), { waitUntil: 'networkidle' });\nconst hasButton = await page.evaluate(() =>\n  [...document.querySelectorAll('button')].some((b) =>\n    /Download (for Social|as GIF)/.test(b.textContent?.trim() || '') && b.getBoundingClientRect().width > 0));\nif (!hasButton) throw new Error('Midjourney download menu not rendered yet — aborting before export');","typeGuard":null,"tryCatchPattern":"try {\n  await downloadRenderedVideo(page, jobId, i, kind, outDir);\n} catch (err) {\n  if (err.message.includes('did not expose')) {\n    await page.reload({ waitUntil: 'networkidle' });\n    await downloadRenderedVideo(page, jobId, i, kind, outDir);\n  } else throw err;\n}","preventionTips":["Wait for the page/action menu to fully render (networkidle or a menu selector) before exporting","Pin or monitor Midjourney UI changes; update button labels promptly after UI updates","Confirm the video job type supports the requested export before attempting","Use an English-locale browser profile so labels match the expected strings"],"tags":["midjourney","ui-automation","selector-mismatch","browser-automation"],"backgroundTag":"dom-element-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}