jackwener/OpenCLI · error · CommandExecutionError
Browser Bridge native click support is required
Error message
Browser Bridge native click support is required
What it means
CommandExecutionError thrown by the Midjourney CLI automation helpers when a browser automation page object does not implement nativeClick. The helper found a visible Midjourney control and computed its screen coordinates, but clicking it requires the Browser Bridge's OS-level (native) click API rather than synthetic DOM events, because some Midjourney UI controls ignore synthetic clicks. The library throws defensively instead of silently failing the interaction.
Solutions
- Upgrade/enable the Browser Bridge so the page object exposes nativeClick(x, y)
- Check feature support before calling: typeof page.nativeClick === 'function' and fall back to page.click on a marked selector otherwise
- Update the opencli client package to match the CLI's expected bridge API
- Fix test mocks/stubs to include a nativeClick no-op
Example fix
// before
await clickVisibleControl(page, 'Switch to Image');
// after
if (typeof page.nativeClick !== 'function') {
throw new Error('This command requires Browser Bridge native click support; update your bridge client');
}
await clickVisibleControl(page, 'Switch to Image'); Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof page.nativeClick !== 'function') {
throw new Error('Browser Bridge nativeClick required; update your bridge client');
} Type guard
const supportsNativeClick = (page) => typeof page?.nativeClick === 'function';
Try / catch
try {
await clickVisibleControl(page, label);
} catch (e) {
if (String(e.message).includes('native click support')) {
throw new Error('Upgrade/enable Browser Bridge to use this command');
}
throw e;
} Prevention
- Pin the browser-bridge client version the CLI was built against
- Feature-check nativeClick before any clickVisibleControl/toggleSettingsPanel call
- Keep mocks in tests updated with nativeClick no-ops
When it happens
Trigger: Calling clickVisibleControl (e.g. clickComposerSubmit flows or 'Switch to Image') against a page object lacking a nativeClick function — typically when the page is driven by a plain automation client instead of the Browser Bridge-enabled bridge page.
Common situations: Using an older browser-bridge client version that predates nativeClick; constructing a fake/mock page in tests without nativeClick; pointing the CLI at a page wrapper from a different automation backend.
Related errors
- composer fill was not verified
- Could not locate Midjourney
- Could not set Midjourney
- Could not submit the Midjourney prompt
- Could not verify Midjourney
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/6fa52fe6eacbad6c.
Report an issue: GitHub.
Appendix: source
Thrown at clis/midjourney/utils.js:1241
}
export async function clickVisibleControl(page, label) {
const target = unwrapEvaluateResult(await page.evaluate((wanted) => {
const visible = (element) => {
const rect = element.getBoundingClientRect();
return rect.width > 0 && rect.height > 0 && getComputedStyle(element).display !== 'none';
};
const button = [...document.querySelectorAll('button')].find((node) => visible(node) && (
node.textContent?.trim().replace(/\s+/g, ' ') === wanted
|| node.title === wanted
|| node.getAttribute('aria-label') === wanted
));
if (!button || button.disabled) return null;
const rect = button.getBoundingClientRect();
return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };
}, label));
if (!target) throw new CommandExecutionError(`Visible Midjourney control "${label}" was not found`);
if (typeof page.nativeClick !== 'function') throw new CommandExecutionError('Browser Bridge native click support is required');
await page.nativeClick(target.x, target.y);
}
export async function clickComposerSubmit(page) {
const marked = unwrapEvaluateResult(await page.evaluate(() => {
document.querySelectorAll('[data-opencli-composer-submit]').forEach((node) => {
node.removeAttribute('data-opencli-composer-submit');
});
const visible = (element) => {
const rect = element.getBoundingClientRect();
return rect.width > 0 && rect.height > 0 && getComputedStyle(element).display !== 'none';
};
const input = document.querySelector('#desktop_input_bar');
const row = input?.parentElement;
if (!input || !row) return false;
const textSubmit = [...row.querySelectorAll('button')]
.find((button) => visible(button) && button.textContent?.trim() === 'Submit');
const following = [...row.querySelectorAll('button')].filter((button) => (View on GitHub (pinned to 49907e53dc)