can1357/oh-my-pi · error · Error

${jobName} has no harbor config.json to resume from

Error message

${jobName} has no harbor config.json to resume from

What it means

ManagerServer throws this when you ask it to resume a harbor job whose job directory contains no config.json. Resume works by re-spawning `runner.ts --resume <jobName> --jobs-dir <jobsDir>`, which requires the original harbor config persisted in `<jobsDir>/<jobName>/config.json`; without it the runner has nothing to resume from. The server treats a missing config as a caller/state error rather than silently failing inside the child.

Source

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

	 * original launch flags from the run's recorded config, so nothing needs
	 * re-specifying. `filterErrorTypes` overrides the default retry set
	 * (every exception type recorded in the job's result.json).
	 */
	resume(jobName: string, opts: { filterErrorTypes?: string[] } = {}): { jobName: string; pid: number } {
		const run = this.#store.getRun(jobName);
		if (!run) throw new Error(`run ${jobName} not found`);
		if (run.benchmark !== "harbor")
			throw new Error(`resume supports only harbor runs (${jobName} is ${run.benchmark})`);
		// Trust liveness, not the recorded status: a runner killed while a
		// previous server instance owned it leaves a stale `running` row with a
		// dead (or null) pid and nobody to fire markExit.
		if (this.#runLive(run)) {
			throw new Error(`run ${jobName} is already running`);
		}
		if (run.status === "running") this.#store.markExit(jobName, null, true);
		const jobDir = path.join(this.jobsDir, jobName);
		if (!fs.existsSync(path.join(jobDir, "config.json"))) {
			throw new Error(`${jobName} has no harbor config.json to resume from`);
		}
		const argv = ["bun", "src/runner.ts", "--resume", jobName, "--jobs-dir", this.jobsDir];
		for (const t of opts.filterErrorTypes ?? erroredExceptionTypes(jobDir)) argv.push("--filter-error-type", t);
		let prewalk: LaunchRequest["prewalk"];
		try {
			prewalk = run.prewalk ? (JSON.parse(run.prewalk) as { into?: string }) : undefined;
		} catch {
			prewalk = undefined;
		}
		const pid = this.#spawnRunner(argv, PKG_DIR, {
			benchmark: "harbor",
			jobName,
			dataset: run.dataset,
			agent: run.agent,
			models: run.models ? run.models.split(",") : [],
			prewalk,
			config: run.config,
			role: run.role,

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the job directory exists and contains config.json: `ls <jobsDir>/<jobName>/config.json`
  2. If the directory is gone, relaunch the job from scratch instead of resuming
  3. If the jobsDir is wrong, restart the manager with the correct --jobs-dir path
  4. If the job name is mistyped, list available jobs (`ls <jobsDir>`) and use the exact name

Example fix

// before
await server.resumeRun("job-42"); // throws: job-42 has no harbor config.json
// after
const jobDir = path.join(jobsDir, "job-42");
if (!fs.existsSync(path.join(jobDir, "config.json"))) {
  await server.launchRun("job-42"); // fresh launch instead of resume
} else {
  await server.resumeRun("job-42");
}
Defensive patterns

Strategy: validation

Validate before calling

import * as fs from "node:fs";
import * as path from "node:path";
function canResume(jobsDir: string, jobName: string): boolean {
  return fs.existsSync(path.join(jobsDir, jobName, "config.json"));
}

Try / catch

try {
  server.resumeRun(jobName);
} catch (err) {
  if (err instanceof Error && err.message.includes("has no harbor config.json")) {
    server.launchRun(jobName); // fall back to a fresh launch
  } else throw err;
}

Prevention

When it happens

Trigger: Calling the resume API (e.g. `resumeRun`/`launchRun` with resume semantics, or the corresponding RPC) for a jobName whose `jobsDir/<jobName>/config.json` does not exist — e.g. resuming a job that was never launched, after the job dir was deleted, or with a typo'd job name.

Common situations: Manual cleanup deleted parts of the jobs directory; the job was created in a different jobsDir and you pointed the server at the wrong `--jobs-dir`; typo in jobName; attempting to resume a job that only got as far as a DB row before config.json was written.

Related errors


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