abhigyanpatwari/GitNexus · error · ValueError

duplicate task id: {task_id}

Error message

duplicate task id: {task_id}

What it means

Raised by select_tasks when a task id has already been added to the `seen` set during the same pass (runner_tasks.py:46-47). Ids must be unique because they key the bindings JSONL, the results aggregation, and the per-task output paths.

Source

Thrown at eval/workflow_bench/runner_tasks.py:47

    skipped: list[str] = []
    seen: set[str] = set()
    required_strings = ("id", "class", "repo", "prompt", "verify")
    optional_strings = ("ref", "setup")
    for index, raw_task in enumerate(tasks):
        if not isinstance(raw_task, Mapping):
            raise ValueError(f"task {index} must be a mapping")
        task = dict(raw_task)
        for field in required_strings:
            if not isinstance(task.get(field), str) or not task[field].strip():
                raise ValueError(f"task {index} requires a nonblank string {field}")
        for field in optional_strings:
            if field in task and not isinstance(task[field], str):
                raise ValueError(f"task {task['id']} field {field} must be a string")
        task_id = task["id"]
        if not re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9._-]{0,127}", task_id):
            raise ValueError(f"task id must be a simple artifact-safe slug: {task_id!r}")
        if task_id in seen:
            raise ValueError(f"duplicate task id: {task_id}")
        seen.add(task_id)
        expensive = task.get("expensive", False)
        if not isinstance(expensive, bool):
            raise ValueError(f"task {task_id} expensive metadata must be boolean")
        copies = task.get("sandbox_copy", [])
        if not isinstance(copies, list) or not all(isinstance(path, str) and path for path in copies):
            raise ValueError(f"task {task_id} sandbox_copy must be a string list")
        dependencies = task.get("sandbox_dependencies", [])
        if not isinstance(dependencies, list):
            raise ValueError(f"task {task_id} sandbox_dependencies must be a list")
        for dependency in dependencies:
            if (
                not isinstance(dependency, Mapping)
                or set(dependency) != {"source", "target"}
                or not all(isinstance(dependency[field], str) and dependency[field] for field in ("source", "target"))
            ):
                raise ValueError(
                    f"task {task_id} sandbox_dependencies entries require nonblank source and target strings"

View on GitHub (pinned to d540b00184)

Solutions

  1. Search the tasks file for the duplicated id and give each occurrence a distinct slug.
  2. Use `yq '.tasks[].id' tasks.yaml | sort | uniq -d` to list all duplicate ids at once.
  3. Re-run after renaming.

Example fix

# before
- id: baseline
  prompt: A
- id: baseline
  prompt: B
# after
- id: baseline-a
  prompt: A
- id: baseline-b
  prompt: B
Defensive patterns

Strategy: validation

Validate before calling

ids = [t.get("id") for t in doc.get("tasks", [])]
dups = {i for i in ids if ids.count(i) > 1}
if dups:
    raise SystemExit(f"duplicate task ids: {sorted(dups)}")

Type guard

def ids_are_unique(tasks: list[dict]) -> bool:
    ids = [t.get("id") for t in tasks]
    return len(ids) == len(set(ids))

Prevention

When it happens

Trigger: Two task mappings share the same id string; copy-pasting a task block and forgetting to rename the id.

Common situations: Duplicating a task to vary only the prompt/ref but leaving the id; merging two YAML task files that both define `baseline`.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12). Data as JSON: /api/errors/86beee81d4d73523. Report an issue: GitHub.