can1357/oh-my-pi · error · Error

run is already running

Error message

run ${jobName} is already running

What it means

Before spawning a runner, launch() checks both this.#children (live child processes this server owns) and the run store for a run whose status is 'running'. If either shows activity for the derived or requested jobName, a duplicate launch is refused to prevent two runners writing the same job directory. This error means the job name is already live.

Solutions

  1. Wait for the existing run to finish, or kill the live runner process before relaunching.
  2. Omit request.jobName or change it — the default name embeds a timestamp, so letting it auto-generate avoids collisions.
  3. Check the store: if the row says 'running' but the pid is dead, mark the exit (the resume path does this via markExit) or restart the server to reconcile.
  4. Add application-level locking in your launcher script to prevent overlapping scheduled launches.

Example fix

// before
server.launch({ model: "m1", jobName: "m1-fixed" }); // called again while running
// after
const run = server.listRuns().find(r => r.jobName === "m1-fixed");
if (!run || run.status !== "running") {
  server.launch({ model: "m1", jobName: "m1-fixed" });
}
Defensive patterns

Strategy: validation

Validate before calling

const jobName = request.jobName ?? defaultName(request);
const live = store.listRuns().some(r => r.jobName === jobName && r.status === "running");
if (live) throw new Error(`${jobName} still running; skipping launch`);

Try / catch

try {
  server.launch(req);
} catch (err) {
  if (err instanceof Error && err.message.includes("is already running")) {
    console.warn(`run ${req.jobName} active; waiting 60s before retry`);
    await Bun.sleep(60_000);
  } else throw err;
}

Prevention

When it happens

Trigger: Calling launch() twice with the same explicit request.jobName while the first is still running; re-running a launch script quickly enough that the previous runner hasn't exited; a stale store row with status 'running' left by a crashed server (no markExit fired); a custom jobName colliding with an existing run.

Common situations: Cron jobs overlapping; CI retry re-invoking launch after a timeout while the first runner is still alive; server restart orphaning 'running' rows; two operators launching the same named experiment concurrently.

Related errors


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

Appendix: source

Thrown at packages/metaharness/src/server.ts:393

			},
		});
	}

	/** Launch any supported benchmark and register it in the uniform run store. */
	launch(request: LaunchRequest): { jobName: string; pid: number } {
		if (!request.model) throw new Error("model is required");
		const benchmark = request.benchmark ?? "harbor";
		if (benchmark !== "harbor" && benchmark !== "edit" && benchmark !== "snapcompact") {
			throw new Error(`unsupported benchmark: ${benchmark}`);
		}
		const dataset =
			request.dataset ??
			(benchmark === "harbor" ? "terminal-bench@2.0" : benchmark === "edit" ? "typescript-edit" : "squad-dev");
		const stamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
		const modelSlug = request.model.replace(/[^a-zA-Z0-9]+/g, "-");
		const jobName = request.jobName ?? `${modelSlug}-${stamp}`;
		if (this.#children.has(jobName) || this.#store.getRun(jobName)?.status === "running") {
			throw new Error(`run ${jobName} is already running`);
		}
		const jobDir = path.join(this.jobsDir, jobName);
		fs.mkdirSync(jobDir, { recursive: true });

		let argv: string[];
		let cwd: string;
		if (benchmark === "edit") {
			cwd = PKG_DIR;
			argv = ["bun", "adapters/edit/cli.ts", "--model", request.model, "--output", path.join(jobDir, "result.json")];
			if (request.tasks !== undefined) argv.push("--max-tasks", String(request.tasks));
			if (request.include?.length) argv.push("--tasks", request.include.join(","));
			if (request.concurrency !== undefined) argv.push("--task-concurrency", String(request.concurrency));
			if (request.attempts !== undefined) argv.push("--runs", String(request.attempts));
		} else if (benchmark === "snapcompact") {
			cwd = PKG_DIR;
			argv = ["uv", "run", "src/adapters/snapcompact.py", "--model", request.model, "--output-dir", jobDir];
			if (request.tasks !== undefined) argv.push("--limit-paras", String(request.tasks));
			if (request.concurrency !== undefined) argv.push("--workers", String(request.concurrency));

View on GitHub (pinned to 9690622007)