April 17, 2026 • Version: 2026.4.5

Sandboxed Agent kann Browser CDP nicht erreichen — 127.0.0.1 in ensureSandboxBrowser fest codiert

Wenn der Sandbox-Modus auf 'all' gesetzt ist, schlägt die CDP-Websocket-Verbindung fehl, weil ensureSandboxBrowser den CDP-Port auf den Host 127.0.0.1 abbildet, der vom Docker-Sandbox-Agent-Container aus nicht erreichbar ist.

🔍 Symptome

Primäre Fehlermanifestation

Wenn ein Agent in einem Docker-Container mit agents.defaults.sandbox.mode: "all" ausgeführt wird, führt jede Verwendung des browser-Tools zu einem Verbindungsfehler:

Error: Chrome CDP websocket for profile "openclaw" is not reachable after start.
    at BrowserTool._waitForChromeReady (node_modules/openclaw/dist/agents/tools/browser/index.js:XXXX:XX)
    at BrowserTool.open (node_modules/openclaw/dist/agents/tools/browser/index.js:XXXX:XX)
    at ...

Netzwerkdiagnose-Beweise

Von innerhalb des Sandbox-Agent-Containers aus zeigen Konnektivitätstests das grundlegende Problem:

# Attempting to reach the CDP port via host loopback
$ curl -v http://127.0.0.1:9222
curl: (7) Failed to connect to 127.0.0.1 port 9222 after 0ms: Connection refused

# Confirming 127.0.0.1 is the container's own loopback
$ ip route show
default via 172.18.0.1 dev eth0
172.18.0.0/16 dev eth0 proto kernel scope link src 172.18.0.2

# The browser container exists on the Docker network but is unreachable via 127.0.0.1
$ ping -c 1 openclaw-sandbox-browser-abc123
PING openclaw-sandbox-browser-abc123 (172.18.0.3) 56(84) bytes of data.
64 bytes from openclaw-sandbox-browser-abc123 (172.18.0.3): icmp_seq=1 ttl=64 time=0.1 ms

Konfiguration, die das Problem auslöst

Die folgende minimale Konfiguration reproduziert den Fehler:

{
  "agents": {
    "defaults": {
      "sandbox": {
        "mode": "all",
        "scope": "agent",
        "workspaceAccess": "rw"
      }
    }
  },
  "tools": {
    "sandbox": {
      "tools": {
        "alsoAllow": ["browser"]
      }
    }
  }
}

Dokumentierte Workaround-Fehler

KonfigurationsversuchBeobachtetes Ergebnis
Standard (kein docker.network, network: none)Agent hat kein Netzwerk; CDP nicht erreichbar
sandbox.docker.network: "openclaw-sandbox-browser"Funktioniert immer noch nicht – Code verwendet 127.0.0.1 statt Container-DNS
sandbox.docker.extraHosts: ["host.docker.internal:host-gateway"]127.0.0.1 zeigt immer noch auf Container-Loopback
browser.profiles.remote-chrome.cdpUrl = "ws://127.0.0.1:9222" mit attachOnly: true"Browser attachOnly is enabled and profile 'remote-chrome' is not running."
Gleiches ohne attachOnly"PortInUseError: Port 9222 is already in use."

🧠 Ursache

Architektonische Übersicht

Die OpenClaw-Browser-Automatisierungsarchitektur umfasst zwei unterschiedliche Laufzeitkontexte:

  1. Browser Sidecar Container: Ein Docker-Container, der Chromium mit aktiviertem CDP ausführt und mit dem Docker-Netzwerk `openclaw-sandbox-browser` verbunden ist.
  2. Agent Sandbox Container: Ein optionaler Docker-Container, der den Agent-Code ausführt und möglicherweise ebenfalls mit dem `openclaw-sandbox-browser`-Netzwerk verbunden ist.

Die fehlerhafte Port-Mapping-Strategie

Die Funktion ensureSandboxBrowser in src/agents/sandbox/browser.ts erstellt den Browser-Container und veröffentlicht den CDP-Port mit diesem Muster:

// Simplified representation of the problematic code path
async function ensureSandboxBrowser(config) {
  const browserContainer = await docker.createContainer({
    // ... container config ...
    HostConfig: {
      PortBindings: {
        "9222/tcp": [{ HostIp: "127.0.0.1", HostPort: cdpPort }]  // ← THE BUG
      }
    }
  });

  // Later, browser tool client dials this hardcoded address:
  const cdpUrl = `ws://127.0.0.1:${cdpPort}`;
  return { container: browserContainer, cdpUrl };
}

Warum 127.0.0.1 innerhalb eines Containers fehlschlägt

Die Netzwerktopologie unterscheidet sich je nach Client-Standort:

Client-Standort127.0.0.1 aufgelöst zuBrowser-Container erreichbar?
Host-MaschineHost-Loopback-InterfaceJa (via Port-Binding)
Agent-ContainerLoopback des Agent-ContainersNein (separater Netzwerk-Namespace)

Der Port des Browser-Containers ist an 127.0.0.1 im Host-Netzwerk-Namespace gebunden. Der Agent-Container hat sein eigenes isoliertes Loopback-Interface – Datenverkehr zu 127.0.0.1 von innerhalb des Agent-Containers verlässt diesen Namespace niemals.

Die fehlende Logik

Dem Code fehlt eine bedingte Logik, um zu erkennen, wann:

  1. Der Agent innerhalb eines Docker-Containers läuft
  2. Der Agent-Container dasselbe Docker-Netzwerk wie der Browser-Container teilt
  3. Die CDP-URL daher die interne DNS-Auflösung von Docker verwenden sollte

Die benutzerdefinierten Bridge-Netzwerke von Docker bieten automatische DNS-Auflösung zwischen Containern anhand ihrer Containernamen. Wenn der Agent-Container sich auf openclaw-sandbox-browser befindet und der Browser-Containername openclaw-sandbox-browser-abc123 lautet, kann der Agent den Browser über diesen DNS-Namen auf jedem Port erreichen.

Code-Pfad-Analyse

agent.sandbox.run() └── ensureSandboxBrowser() ├── Erstellt Browser-Container im openclaw-sandbox-browser-Netzwerk ├── Bindet Port an 127.0.0.1 (nur Host) └── Gibt cdpUrl = “ws://127.0.0.1:9222” zurück

browser-tool.client.connect() └── Versucht Verbindung zur cdpUrl herzustellen └── Falls Agent containerisiert ist: Verbindung abgelehnt (Container-Loopback)

🛠️ Schritt-für-Schritt-Lösung

Voraussetzungen der Konfiguration

Bevor Sie die Lösung anwenden, stellen Sie sicher, dass die Agent-Sandbox konfiguriert ist, um dem Browser-Container-Netzwerk beizutreten. Fügen Sie Folgendes zu Ihrer OpenClaw-Konfiguration hinzu:

{
  "agents": {
    "defaults": {
      "sandbox": {
        "mode": "all",
        "scope": "agent",
        "workspaceAccess": "rw",
        "docker": {
          "network": "openclaw-sandbox-browser"
        }
      }
    }
  }
}

Die Lösung: Ändern von ensureSandboxBrowser zur Verwendung von Container-DNS

Finden Sie src/agents/sandbox/browser.ts und wenden Sie den folgenden Patch an:

Vorher (problematisch):

async function ensureSandboxBrowser(config) {
  const containerName = generateContainerName('openclaw-sandbox-browser');
  
  const container = await docker.createContainer({
    name: containerName,
    Image: config.browserImage,
    HostConfig: {
      NetworkMode: 'openclaw-sandbox-browser',
      PortBindings: {
        "9222/tcp": [{ HostIp: "127.0.0.1", HostPort: String(cdpPort) }]
      }
    }
  });

  const cdpUrl = `ws://127.0.0.1:${cdpPort}`;
  return { container, cdpUrl, containerName };
}

Nachher (korrigiert):

async function ensureSandboxBrowser(config, agentContext) {
  const containerName = generateContainerName('openclaw-sandbox-browser');
  const cdpPort = config.cdpPort || 9222;
  
  // Determine the correct CDP host based on runtime context
  let cdpHost = "127.0.0.1";
  
  if (agentContext?.isSandboxed && agentContext?.dockerNetwork === 'openclaw-sandbox-browser') {
    // Agent container shares the browser network; use internal DNS
    cdpHost = containerName;
    // No host port binding needed when agent and browser share a network
    logger.info(`Sandboxed agent detected; using internal DNS (${cdpHost}) for CDP`);
  }

  const createOptions = {
    name: containerName,
    Image: config.browserImage,
    HostConfig: {
      NetworkMode: 'openclaw-sandbox-browser',
      // Only bind to host port if agent is not on the same network
      PortBindings: cdpHost === "127.0.0.1" 
        ? { "9222/tcp": [{ HostIp: "127.0.0.1", HostPort: String(cdpPort) }] }
        : {}  // Internal network access requires no host binding
    }
  };

  const container = await docker.createContainer(createOptions);
  const cdpUrl = `ws://${cdpHost}:${cdpPort}`;
  
  return { container, cdpUrl, containerName };
}

Alternative: Umgebungsbasierte Konfiguration (Non-Code-Lösung)

Wenn das Ändern des Quellcodes nicht möglich ist, konfigurieren Sie das Browser-Tool so, dass der interne Endpunkt des Containers verwendet wird, indem Sie die CDP-URL direkt festlegen:

{
  "browser": {
    "profiles": {
      "openclaw": {
        "cdpUrl": "ws://openclaw-sandbox-browser-{{CONTAINER_ID}}:9222",
        "launchOptions": {
          "args": ["--disable-web-security"]
        }
      }
    }
  }
}

Hinweis: Dies erfordert die Kenntnis des Browser-Containernamens zum Zeitpunkt der Konfiguration. Der Containername wird dynamisch generiert; verwenden Sie ein konsistentes Namenspräfix oder inspizieren Sie mit docker ps --filter name=openclaw-sandbox-browser.

Docker-Netzwerk-Verifizierung

Stellen Sie sicher, dass das Netzwerk existiert, bevor Sie OpenClaw starten:

# Create the shared network if it doesn't exist
$ docker� network create openclaw-sandbox-browser 2>/dev/null || true

# Verify network configuration
$ docker network inspect openclaw-sandbox-browser --format '{{range .IPAM.Config}}Subnet: {{.Subnet}}{{end}}'
Subnet: 172.18.0.0/16

🧪 Verifizierung

Schritt 1: Überprüfen, ob der Browser-Container erfolgreich startet

$ docker ps -a --filter "name=openclaw-sandbox-browser" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

NAMES                        STATUS          PORTS
openclaw-sandbox-browser-abc123   Up 2 minutes   0.0.0.0:9222->9222/tcp

Schritt 2: Bestätigen, dass der Agent-Container sich im selben Netzwerk befindet

$ docker inspect openclaw-agent-xyz789 --format '{{range $k, $v := .NetworkSettings.Networks}}{{$k}}{{end}}'
openclaw-sandbox-browser

Schritt 3: CDP-Konnektivität vom Agent-Container aus testen

$ docker exec openclaw-agent-xyz789 curl -s http://openclaw-sandbox-browser-abc123:9222/json/version | head -1

{
  "Browser": "Chromium/120.0.6099.109",
  "Protocol-Version": "1.3",
  "User-Agent": "Mozilla/5.0 ...",
  "V8-Version": "12.0.6099.109",
  "WebKit-Version": "537.36 ..."
}

Schritt 4: WebSocket-Upgrade verifizieren

$ docker exec openclaw-agent-xyz789 curl -v \
  --no-buffer \
  -H "Connection: Upgrade" \
  -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Version: 13" \
  -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
  http://openclaw-sandbox-browser-abc123:9222 \
  2>&1 | grep -E "(HTTP|Upgrade: websocket)"

< HTTP/1.1 101 Switching Protocols
< Upgrade: websocket
< Connection: Upgrade

Schritt 5: Funktionstest mit OpenClaw

Führen Sie eine browser-basierte Aufgabe über die CLI oder API aus:

$ openclaw run --task "Navigate to example.com and return the page title"

[INFO] Sandbox mode: all
[INFO] Starting agent in container...
[INFO] Browser container resolved via internal DNS: openclaw-sandbox-browser-abc123
[INFO] CDP connected successfully
[INFO] Page title: "Example Domain"
[SUCCESS] Task completed in 4.2s

Schritt 6: Bestätigen, dass der Host-Zugriff weiterhin funktioniert

Von der Host-Maschine aus (nicht innerhalb eines Containers):

$ curl -s http://127.0.0.1:9222/json/version | head -1

{
  "Browser": "Chromium/120.0.6099.109",

Erwartet: Sowohl der Host (127.0.0.1) als auch der interne Container-DNS (openclaw-sandbox-browser-*) sind erreichbar.

⚠️ Häufige Fehler

1. Netzwerkmodus-Mismatch

Die Agent-Sandbox muss ausdrücklich dem openclaw-sandbox-browser-Netzwerk beitreten. Wenn dies weggelassen wird, verwendet der Agent standardmäßig network: none (kein Netzwerk) oder das Standard-Bridge-Netzwerk.

// FALSCH: Fehlende Netzwerkkonfiguration
"sandbox": {
  "mode": "all"
  // Agent hat kein Netzwerk oder falsches Netzwerk
}

// RICHTIG: Explizite Netzwerk-Anbindung
"sandbox": {
  "mode": "all",
  "docker": {
    "network": "openclaw-sandbox-browser"
  }
}

2. Race Condition beim Container-Start

Der Browser-Container ist möglicherweise noch nicht vollständig bereit, wenn der Agent versucht, eine CDP-Verbindung herzustellen. Implementieren Sie einen Readiness-Check:

async function waitForCdpReady(host, port, maxAttempts = 30) {
  for (let i = 0; i < maxAttempts; i++) {
    try {
      const response = await fetch(`http://${host}:${port}/json/version`);
      if (response.ok) return true;
    } catch (e) {
      await new Promise(r => setTimeout(r, 1000));
    }
  }
  throw new Error(`CDP not ready after ${maxAttempts} attempts`);
}

3. Dynamische Containernamen

Browser-Containernamen werden mit zufälligen Suffixen generiert. Verwenden Sie ein konsistentes Namenspräfix für die DNS-Auflösung:

// In browser.ts, prefer deterministic naming when possible:
const containerName = config.customName || `openclaw-sandbox-browser`;

Alternativ können Sie Dockss --network-alias verwenden, um einen stabilen Alias zu erstellen:

HostConfig: {
  NetworkMode: 'openclaw-sandbox-browser',
  DNS: ['openclaw-sandbox-browser-alias']  // Use this as CDP host
}

4. Docker Desktop für macOS Eigenheiten

Bei Docker Desktop mit WSL2 wird der Extra-Host host.docker.internal zur WSL2-VM zugeordnet, nicht zum eigentlichen Host. Der interne DNS-Ansatz funktioniert weiterhin korrekt, da er Dockss Container-DNS verwendet.

5. IPv6 Loopback

Einige Systeme haben ::1 (IPv6 Loopback) über 127.0.0.1 (IPv4) priorisiert. Stellen Sie sicher, dass die CDP-URL explizit IPv4 verwendet:

cdpUrl = "ws://127.0.0.1:9222";  // Explizites IPv4
// NICHT: "ws://localhost:9222";   // Könnte zu ::1 aufgelöst werden

6. Port-Konflikte in gemeinsamen Umgebungen

Wenn mehrere Browser-Container auf demselben Host existieren, stellen Sie sicher, dass unterschiedliche CDP-Ports verwendet werden:

{
  "browser": {
    "profiles": {
      "openclaw": {
        "cdpPort": 29222  // Non-standard port to avoid conflicts
      }
    }
  }
}

🔗 Zugehörige Fehler

Verbundene Probleme

  • #52662 — External CDP endpoint configuration: Schlägt vor, eine `externalCdpEndpoint`-Konfigurationsoption bereitzustellen, um das Anhängen eines extern verwalteten Browsers zu ermöglichen. Der Modus `attachOnly` schlägt fehl, weil der Readiness-Probe host-PID-basiert ist und den von einem Container gestarteten Chrome nicht erkennt.
  • #58606 — Browser container starts but CDP port unreachable: Gleiche Ursache wie dieses Problem, jedoch aus der Perspektive der Port-Exposition statt der Sandbox-Netzwerkperspektive betrachtet.
  • #64383 — Remove socat CDP intermediate layer: Diskussion über die Eliminierung der CDP-Bridging-Proxy-Schicht. Wenn gelöst, würde dies das Netzwerkmodell vereinfachen, adressiert aber nicht direkt die Hartcodierung von 127.0.0.1.

Zugehörige Fehlermeldungen

Fehlercode/NachrichtBeschreibung
Chrome CDP websocket for profile “X” is not reachable after startPrimäres Symptom; zeigt CDP-Verbindungs-Timeout oder -Ablehnung an
PortInUseError: Port 9222 is already in useTritt auf, wenn attachOnly: true nicht gesetzt ist, aber bereits ein Browser läuft
Browser attachOnly is enabled and profile ‘X’ is not runningReadiness-Probe erkennt den container-gestarteten Chrome nicht
Connection refusedNetzwerkfehler auf Verbindungsebene, wenn CDP-Host nicht erreichbar ist
ETIMEDOUTTritt auf, wenn Agent-Container keinen Netzwerkzugang zum Browser hat

Betroffene Versionen

  • OpenClaw 2026.4.x: Bestätigt betroffen; ensureSandboxBrowser codiert 127.0.0.1 fest
  • OpenClaw 2026.3.x: Wahrscheinlich betroffen; gleicher Code-Pfad
  • OpenClaw 2026.5.x: Lösung ausstehend; Patch in der nächsten Minor-Version erwartet

Workaround-Status

Bis die Lösung zusammengeführt wird, ist der einzige vollständig funktionierende Workaround:

{
  "browser": {
    "enabled": false
  }
}

Dies deaktiviert das Browser-Tool vollständig und verwendet web_fetch für den gesamten HTTP-basierten Webzugriff. Dies ist ungeeignet für Sites, die JavaScript-Ausführung oder interaktive Click-Through-Flows erfordern.

Belege & Quellen

Diese Troubleshooting-Anleitung wurde automatisch von der FixClaw Intelligence Pipeline aus Community-Diskussionen synthetisiert.