can1357/oh-my-pi · error

Terminal-Bench tasks directory contains no task.toml files:

Error message

Terminal-Bench tasks directory contains no task.toml files: ${absolute}

What it means

validateTasksDir also throws when the directory exists and is readable but none of its immediate subdirectories contain a task.toml file — meaning it is not a Terminal-Bench tasks root (you may have pointed at the repo root instead of its tasks/ folder, or at the wrong checkout level).

Source

Thrown at packages/metaharness/src/tb/dataset.ts:32

	} catch (error) {
		if (isEnoent(error)) return "missing";
		throw error;
	}
}

async function validateTasksDir(tasksDir: string): Promise<string> {
	const absolute = path.resolve(tasksDir);
	try {
		const entries = await fs.readdir(absolute, { withFileTypes: true });
		for (const entry of entries) {
			if (!entry.isDirectory()) continue;
			if (await Bun.file(path.join(absolute, entry.name, "task.toml")).exists()) return absolute;
		}
	} catch (error) {
		if (isEnoent(error)) throw new Error(`Terminal-Bench tasks directory does not exist: ${absolute}`);
		throw error;
	}
	throw new Error(`Terminal-Bench tasks directory contains no task.toml files: ${absolute}`);
}

function repositoryName(source: string): string {
	const trimmed = source.replace(/\/+$/, "");
	const basename = trimmed.slice(trimmed.lastIndexOf("/") + 1).replace(/\.git$/, "");
	if (!basename) throw new Error(`Cannot determine repository name from dataset source: ${source}`);
	return basename;
}

function gitError(action: string, source: string, stderr: Uint8Array): Error {
	const detail = new TextDecoder().decode(stderr).trim();
	return new Error(`${action} ${source} failed${detail ? `: ${detail}` : ""}`);
}

export async function resolveDataset(source: string, cacheDir: string): Promise<string> {
	const sourceKind = await directoryStat(source);
	if (sourceKind === "directory") {
		const absoluteSource = path.resolve(source);

View on GitHub (pinned to 9690622007)

Solutions

  1. Point --dataset at the directory whose subdirectories each contain task.toml (often <repo>/tasks)
  2. Verify the cloned repo is intact (git status; non-empty tasks/) and re-clone if needed
  3. If layout changed upstream, pass the nested tasks path explicitly (resolveDataset already tries <dir>/tasks)

Example fix

// before
--dataset ~/terminal-bench          # repo root, no */task.toml
// after
--dataset ~/terminal-bench/tasks    # contains hello-world/task.toml ...
Defensive patterns

Strategy: validation

Validate before calling

import * as fs from "node:fs/promises";
import * as path from "node:path";
const entries = await fs.readdir(dir, { withFileTypes: true });
const hasTask = entries.some(async e => e.isDirectory() && await Bun.file(path.join(dir, e.name, "task.toml")).exists());
if (!hasTask) throw new Error(`${dir} has no */task.toml`);

Prevention

When it happens

Trigger: resolveDataset passes a directory whose child directories all lack task.toml, e.g. pointing at a Terminal-Bench repo root instead of tasks/, or a checkout of a different project.

Common situations: Dataset dir has an unexpected layout after upstream restructure; user passed a parent directory; empty cloned repo (shallow/failed checkout with no task subdirs).

Related errors


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