can1357/oh-my-pi · error · Error
run ${jobName} 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.
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)
Solutions
- Wait for the existing run to finish, or kill the live runner process before relaunching.
- Omit request.jobName or change it — the default name embeds a timestamp, so letting it auto-generate avoids collisions.
- 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.
- 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
- Rely on the timestamped default jobName instead of fixed custom names.
- Add a mutex/lock file around scheduled launches to prevent overlap.
- Check run status before relaunching after CI timeouts.
- After a server crash, reconcile stale 'running' rows (dead pid -> markExit) before relaunching.
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
- Marketplace "${catalog.name}" already exists
- Daemon ${spec.name} is already starting
- arm '${req.arm}' already exists in '${experimentId}'
- ManualTriageConflict(delivery, existing.state)
- native spelling thread stopped
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/5d3074559aadf497.
Report an issue: GitHub.