Skip to content

A2UI content disappears immediately due to auto-navigation reload loop #22292

@carlvellotti

Description

@carlvellotti

Bug Description

A2UI content renders momentarily then disappears because the macOS app's auto-navigation logic reloads the WebView in a loop. There are two related bugs:

Bug 1: shouldAutoNavigateToA2UI() returns wrong value (critical)

File: apps/macos/Sources/OpenClaw/CanvasWindowController.swift, line ~369

In shouldAutoNavigateToA2UI(lastAutoTarget:), when currentTarget == lastAutoTarget (i.e., the WebView is already showing the A2UI URL), the method returns true — causing the page to reload even though it's already at the correct URL. This should return false.

func shouldAutoNavigateToA2UI(lastAutoTarget: String?) -> Bool {
    let trimmed = (self.currentTarget ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
    if trimmed.isEmpty || trimmed == "/" { return true }
    if let lastAuto = lastAutoTarget?.trimmingCharacters(in: .whitespacesAndNewlines),
       !lastAuto.isEmpty,
       trimmed == lastAuto
    {
        return true  // BUG: should be `return false`
    }
    return false
}

This gets triggered from two paths:

  1. Gateway snapshot observer (CanvasManager.startGatewayObserver) — every gateway snapshot push triggers handleGatewayPushmaybeAutoNavigateToA2UIcontroller.load(target:), reloading the page
  2. CanvasManager.eval() — calls self.show(sessionKey:, path: nil) before every eval, which triggers maybeAutoNavigateToA2UIAsync, causing another reload

The result is that any A2UI content rendered via applyMessages() is immediately wiped by the page reload.

Bug 2: Gateway serves .js files with wrong MIME type

The gateway's static file server uses detectMime() which relies on file content sniffing. For JavaScript files (including a2ui.bundle.js), this returns application/octet-stream instead of application/javascript. The browser then refuses to execute the script.

File: src/cli/gateway-cli.ts (or wherever the canvas static server constructs MIME types)

The fix is to check file extension before falling back to content-based detection:

.js  → application/javascript; charset=utf-8
.css → text/css; charset=utf-8
.json/.map → application/json; charset=utf-8

Steps to Reproduce

  1. Start gateway with canvasHost.enabled: true
  2. Connect macOS app as node
  3. Run openclaw nodes canvas a2ui push --text "Hello" (or any A2UI JSONL)
  4. Observe: content flashes briefly then the canvas goes blank

Expected Behavior

A2UI content should render and persist on the canvas until explicitly replaced.

Environment

  • OpenClaw CLI: v2026.1.29
  • OpenClaw macOS app: v2026.2.19
  • macOS: Darwin 24.3.0

Workaround

Bug 2 (MIME type) can be patched in the compiled gateway dist file by adding extension checks before detectMime(). Bug 1 (auto-navigation) requires rebuilding the macOS app from source — no runtime workaround found.

Metadata

Metadata

Assignees

No one assigned

    Labels

    staleMarked as stale due to inactivity

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions