coleam00/Archon · error

Container overlay did not become ready.${logs ? ` Container

Error message

Container overlay did not become ready.${logs ? ` Container logs:\n${logs}` : ''}

What it means

waitForReady polls the container until its overlay setup signals readiness. On timeout/exit it captures the last 20 lines of container logs and throws this error with those logs attached for diagnosis.

Source

Thrown at packages/isolation/src/backends/container.ts:693

        return;
      } catch {
        // Not ready yet. ONLY fast-fail when the container has DEFINITELY exited
        // (`Running=false`) — a transient inspect error/timeout must NOT be read
        // as "stopped", or an infra blip would silently trigger the native +
        // CAP_SYS_ADMIN fallback (privilege broadening). On 'unknown' keep polling
        // until the deadline (a real exit still surfaces via the timeout).
        if ((await this.containerState(containerId)) === 'stopped') break;
        await new Promise(resolve => setTimeout(resolve, READY_POLL_INTERVAL_MS));
      }
    }
    let logs = '';
    try {
      const { stdout, stderr } = await this.docker(['logs', '--tail', '20', containerId]);
      logs = `${stdout}\n${stderr}`.trim();
    } catch {
      // Best-effort — the timeout / exit is the real error.
    }
    throw new Error(
      `Container overlay did not become ready.${logs ? ` Container logs:\n${logs}` : ''}`
    );
  }

  /**
   * Container running state as three distinct outcomes. Crucially, an inspect
   * ERROR (daemon timeout, transient failure) is `unknown`, NOT `stopped` — the
   * caller must not treat "couldn't tell" as "exited" (see waitForReady: only an
   * explicit `stopped` may fast-fail into the privileged native fallback).
   */
  private async containerState(containerId: string): Promise<'running' | 'stopped' | 'unknown'> {
    try {
      const { stdout } = await this.docker(['inspect', '-f', '{{.State.Running}}', containerId], {
        timeout: 5_000,
      });
      const value = stdout.trim();
      if (value === 'true') return 'running';
      if (value === 'false') return 'stopped';

View on GitHub (pinned to 0773b97458)

Solutions

  1. Read the attached container logs in the error message to find the mount failure
  2. Verify the runner image contains the overlay init script and it runs to completion
  3. Increase the readiness timeout on slow hosts
  4. Ensure /dev/fuse and required capabilities are present when using fuse-overlayfs
Defensive patterns

Strategy: try-catch

Validate before calling

// verify image contains the overlay init script before starting
docker run --rm <image> test -x /path/to/overlay-init || echo 'image missing init script'

Try / catch

try {
  await backend.resumeEnv(envId);
} catch (err) {
  if (String(err).startsWith('Container overlay did not become ready')) {
    // err.message contains the last 20 container log lines — inspect them
    const logs = err.message.split('Container logs:\n')[1];
    console.error('readiness logs:', logs);
  }
  throw err;
}

Prevention

When it happens

Trigger: A container started via startContainerWithOverlay or resumed via resumeEnv never emits its ready signal within the timeout — the overlay mount script hangs or the container crashes during init.

Common situations: fuse-overlayfs stalling on a misconfigured /dev/fuse; runner image missing the ready-signal script; slow host I/O exceeding the readiness timeout; container OOM-killed during mount.

Related errors


AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01). Data as JSON: /api/errors/f4456cd52bd96edc. Report an issue: GitHub.