Skip to content

fix: await async VirtualDisplay.get() (fixes 'cannot open display: [object Promise]' on Docker/Linux)#5651

Open
Kyzcreig wants to merge 1 commit into
jo-inc:masterfrom
Kyzcreig:fix/await-virtual-display-get
Open

fix: await async VirtualDisplay.get() (fixes 'cannot open display: [object Promise]' on Docker/Linux)#5651
Kyzcreig wants to merge 1 commit into
jo-inc:masterfrom
Kyzcreig:fix/await-virtual-display-get

Conversation

@Kyzcreig

Copy link
Copy Markdown

Problem

camoufox-js's VirtualDisplay.get() is async (returns Promise<string> like ':0'), but launchBrowserInstance() in server.js calls it without await:

vdDisplay = localVirtualDisplay.get();

So vdDisplay is a Promise, which is then passed to launchOptions({ virtual_display: vdDisplay }) and stringified to "[object Promise]". Every Camoufox launch on Linux/Docker then fails with:

Error: cannot open display: [object Promise]

This breaks the Docker deployment entirely/health shows browserRunning: false, browserConnected: false, the background pre-warm retries forever, and every POST /tabs returns 500 Internal server error. The log shows the tell: "xvfb virtual display started", "display": {} (an unresolved Promise rendered as {}) immediately followed by the launch failure.

Fix

Add the missing await:

vdDisplay = await localVirtualDisplay.get();

launchBrowserInstance() is already async and awaits launchOptions(...) a few lines below, so this is safe. After the fix the log correctly shows "display": ":0" and "camoufox launched".

Verification

Built the image (make build && make up) on an arm64 Mac (Docker), confirmed:

  • GET /health{"ok":true,"browserConnected":true,"browserRunning":true,...}
  • POST /tabs for https://nowsecure.nl (a Cloudflare bot-detection test page) → tab created, GET /tabs/:id/snapshot returns the success content (NOWSECURE headings) with no Cloudflare interstitial.

One-line change; no behavior change beyond fixing the broken Linux/virtual-display launch path.

camoufox-js's VirtualDisplay.get() is async (returns Promise<string> like
':0'), but server.js called it without await:

    vdDisplay = localVirtualDisplay.get();

So vdDisplay was a Promise, passed to launchOptions({ virtual_display }) and
stringified to '[object Promise]', causing every browser launch on Linux/Docker
to fail with:

    Error: cannot open display: [object Promise]

This breaks the Docker deployment entirely (browserRunning stays false; every
/tabs request 500s). Add the missing await so a real display string (':0') is
passed. Verified: browser launches, /tabs works, beats a Cloudflare bot-test
page.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant