can1357/oh-my-pi · error · Error
run ${jobName} is running; cancel it first
Error message
run ${jobName} is running; cancel it first What it means
deleteRun removes a run's DB rows and on-disk artifacts (job dir and manager log), but refuses while the run is live: if `#runLive(run)` is true it throws telling you to cancel the run first. Unknown job names return false instead of throwing.
Source
Thrown at packages/metaharness/src/server.ts:576
`experiment ${id} has running arms (${live.map(r => r.jobName).join(", ")}); cancel them first`,
);
}
for (const run of runs) this.#destroyRun(run.jobName);
this.#store.deleteExperimentMeta(id);
this.#tick();
return { id, deletedRuns: runs.map(r => r.jobName) };
}
/**
* Permanently delete a run: DB row + trials, job dir, and manager log.
* Disk removal is not optional — discover() would resurrect a surviving
* job dir as a fresh row on the next restart. Refuses while the run is
* live; returns false when the run is unknown.
*/
deleteRun(jobName: string): boolean {
const run = this.#store.getRun(jobName);
if (!run) return false;
if (this.#runLive(run)) throw new Error(`run ${jobName} is running; cancel it first`);
this.#destroyRun(jobName);
this.#tick();
return true;
}
/** Remove a run's DB rows and on-disk artifacts (job dir + manager log). */
#destroyRun(jobName: string): void {
assertSafeJobName(jobName);
this.#store.deleteRun(jobName);
fs.rmSync(path.join(this.jobsDir, jobName), { recursive: true, force: true });
fs.rmSync(path.join(this.jobsDir, "_manager", "logs", `${jobName}.log`), { force: true });
}
/** Add a comparable arm to an existing experiment, inheriting its sample + config. */
addArm(experimentId: string, req: AddArmRequest): { jobName: string; pid: number } {
return this.launch(resolveArmLaunch(this.#store, experimentId, req));
}
View on GitHub (pinned to 9690622007)
Solutions
- Cancel the run first (cancel API), then delete it
- Wait for the run to finish before deleting
- If the process is actually dead but state is stale, restart the manager (which reaps state, e.g. markExit on restart) and retry
Example fix
// before
server.deleteRun("job-7"); // throws: run job-7 is running
// after
if (server.isRunLive?.("job-7")) server.cancelRun("job-7");
server.deleteRun("job-7"); Defensive patterns
Strategy: validation
Validate before calling
function canDeleteRun(server: ManagerServer, jobName: string): boolean {
const run = server.getRun(jobName);
return !!run && !server.isRunRunning(jobName);
} Try / catch
try {
server.deleteRun(jobName);
} catch (err) {
if (err instanceof Error && /is running; cancel it first/.test(err.message)) {
server.cancelRun(jobName);
server.deleteRun(jobName);
} else throw err;
} Prevention
- Check run status before delete
- Cancel live runs first in cleanup tooling
- Remember unknown runs return false, only live runs throw
- Clear stale running state via manager restart
When it happens
Trigger: Calling `deleteRun(jobName)` while the run's process is still executing (live per `#runLive`).
Common situations: A cleanup routine deleting jobs without checking status; attempting to purge a run that is mid-trial; operator deletes the wrong still-active job.
Related errors
- experiment ${id} has running arms (${live.map(r => r.jobName
- Daemon broker client is closed
- Live transport is not connected
- MCP server not connected: ${name}
- Transport not connected
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/b6ceaf1feb3b9d44.
Report an issue: GitHub.