can1357/oh-my-pi · error

Vibemon VM ${sandbox.id} entered ${state} before becoming re

Error message

Vibemon VM ${sandbox.id} entered ${state} before becoming ready

What it means

waitUntilRunning polls the Vibemon sandbox's observed state until it reports running. If the sandbox instead reports a terminal state (exited, failed, stopped, or terminated) before ever becoming ready, this error is thrown immediately with the VM id and the observed state, rather than waiting out the whole timeout.

Source

Thrown at packages/metaharness/src/tb/vmon.ts:66

function clientFor(config: VmonConfig): Client {
	const key = `${config.url}\0${config.token}`;
	let client = clients.get(key);
	if (!client) {
		client = connect(config.url, { token: config.token || undefined });
		clients.set(key, client);
	}
	return client;
}

async function waitUntilRunning(sandbox: Sandbox, timeoutSec: number): Promise<void> {
	const deadline = Date.now() + timeoutSec * 1_000;
	while (Date.now() < deadline) {
		const info = await sandbox.refresh();
		const state = String(info.observed_state ?? info.status ?? "").toLowerCase();
		if (state === "running") return;
		if (["exited", "failed", "stopped", "terminated"].includes(state)) {
			throw new Error(`Vibemon VM ${sandbox.id} entered ${state} before becoming ready`);
		}
		await Bun.sleep(250);
	}
	throw new Error(`Timed out waiting ${timeoutSec} seconds for Vibemon VM ${sandbox.id} to become ready`);
}

async function archiveDirectory(root: string): Promise<Blob> {
	const entries: Record<string, Uint8Array> = {};
	const visit = async (dir: string): Promise<void> => {
		for (const entry of await fs.readdir(dir, { withFileTypes: true })) {
			const absolute = path.join(dir, entry.name);
			if (entry.isDirectory()) {
				await visit(absolute);
			} else if (entry.isFile()) {
				const relative = path.relative(root, absolute).split(path.sep).join("/");
				entries[relative] = new Uint8Array(await Bun.file(absolute).arrayBuffer());
			}
		}

View on GitHub (pinned to 9690622007)

Solutions

  1. Inspect VM/container logs for the sandbox id reported in the message to find the boot failure
  2. Validate the VM image boots standalone (run it locally with the same entrypoint)
  3. Increase host memory/CPU or reduce concurrent sandboxes to avoid OOM/preemption
  4. Check for other processes or cleanup jobs stopping the sandbox during startup

Example fix

// before: crashed image
new Vibemon({ image: "my-vm:broken" })
// after: validated image that reaches running state
new Vibemon({ image: "my-vm:fixed", resources: { memoryMB: 4096 } })
Defensive patterns

Strategy: retry

Try / catch

try {
  await vm.start();
} catch (err) {
  if (/entered (exited|failed|stopped|terminated) before becoming ready/.test(err.message)) {
    const logs = await fetchSandboxLogs(vm.id);
    logger.error("VM boot failed", { id: vm.id, logs });
    throw err; // boot failure is usually not transient; surface with logs
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling start() on a Vibemon VM whose container/VM exits, fails, stops, or is terminated during the readiness poll window — e.g. image crash on boot, bad entrypoint, OOM kill, or externally issued stop.

Common situations: Broken VM image that crashes at startup; insufficient host resources causing OOM; orchestrator preempting the sandbox; concurrent run killing the sandbox by name.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/f3dafaefc86e72b5. Report an issue: GitHub.