From 679b90a667d55f7967b725c2e2a5ef1a23198220 Mon Sep 17 00:00:00 2001 From: cynarAI <155274210+cynarAI@users.noreply.github.com> Date: Fri, 23 Oct 2026 05:23:00 +0200 Subject: [PATCH] Recreate a computer whose Docker network was removed (#226) When a stack restart or network prune removes a bot's network, its stopped computer keeps pointing at the old network id. Starting it fails with "network ... not found", the supervisor returned 500 on every provision, and runs for that bot retried setup forever while staying queued. The supervisor now recognizes that error and recreates the container on a fresh network with the same home, as it already does for an outdated image. Claude-Session: https://claude.ai/code/session_01QAiXRe1FLMAJT9jkvwFZFq Co-authored-by: Claude --- infra/sandboxes/supervisor/src/index.test.ts | 15 +++++++++++ infra/sandboxes/supervisor/src/index.ts | 25 ++++++++++++++----- .../supervisor/src/supervisor-logic.ts | 5 ++++ 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/infra/sandboxes/supervisor/src/index.test.ts b/infra/sandboxes/supervisor/src/index.test.ts index 8bdb03d..fff3b4e 100644 --- a/infra/sandboxes/supervisor/src/index.test.ts +++ b/infra/sandboxes/supervisor/src/index.test.ts @@ -30,6 +30,7 @@ import { hasValidBearerToken, interactiveScreenCommand, isComputerControlUnavailable, + isMissingNetworkError, nextScreenIndex, normalizeWorkspaceRelative, parseObservation, @@ -846,3 +847,17 @@ describe("docker exec stream demux", () => { }); }); }); + +describe("isMissingNetworkError", () => { + it("recognizes Docker refusing to start a container whose network is gone", () => { + expect( + isMissingNetworkError( + new Error( + "(HTTP code 404) no such container - failed to set up container networking: network 065709cd6047a1b2 not found", + ), + ), + ).toBe(true); + expect(isMissingNetworkError(new Error("(HTTP code 404) no such container"))).toBe(false); + expect(isMissingNetworkError(new Error("image not found"))).toBe(false); + }); +}); diff --git a/infra/sandboxes/supervisor/src/index.ts b/infra/sandboxes/supervisor/src/index.ts index 598efc2..e81e9a7 100644 --- a/infra/sandboxes/supervisor/src/index.ts +++ b/infra/sandboxes/supervisor/src/index.ts @@ -71,6 +71,7 @@ import { hasValidBearerToken, interactiveScreenCommand, isComputerControlUnavailable, + isMissingNetworkError, nextScreenIndex, normalizeWorkspaceRelative, parseObservation, @@ -287,12 +288,24 @@ app.post("/computers", async (c) => { (!brokerSocketDir || githubBrokerSocketMounted(info.Mounts)) && extraBindsMounted(info.Mounts, resolveExtraBinds()) ) { - if (!info.State.Running) await existing.start(); - return c.json({ - id: existing.id, - image: COMPUTER_IMAGE, - resumed: true, - }); + // A container whose network was removed (a stack restart or network prune) + // never starts again; recreate it below on a fresh network with the same home. + const running = + info.State.Running || + (await existing.start().then( + () => true, + (error: unknown) => { + if (isMissingNetworkError(error)) return false; + throw error; + }, + )); + if (running) { + return c.json({ + id: existing.id, + image: COMPUTER_IMAGE, + resumed: true, + }); + } } } diff --git a/infra/sandboxes/supervisor/src/supervisor-logic.ts b/infra/sandboxes/supervisor/src/supervisor-logic.ts index 58962b5..fa469e1 100644 --- a/infra/sandboxes/supervisor/src/supervisor-logic.ts +++ b/infra/sandboxes/supervisor/src/supervisor-logic.ts @@ -83,6 +83,11 @@ export async function preferComputerControl( } } +/** Docker cannot start a container whose network was removed underneath it. */ +export function isMissingNetworkError(error: unknown) { + return /network \S+ not found/i.test(error instanceof Error ? error.message : String(error)); +} + export class ComputerControlUnavailableError extends Error { constructor(message = "computer control unavailable") { super(message);