HKUDS/Vibe-Trading · error · ValueError

duplicate skill names in manifest input: {names}

Error message

duplicate skill names in manifest input: {names}

What it means

When skills is passed as a sequence (not a Mapping), build_run_manifest sorts records by name and rejects duplicates — two SkillRecords with the same name make the manifest ambiguous.

Source

Thrown at agent/src/governance/manifest.py:407

            two records with the same name.
    """
    if not run_id or not run_id.strip():
        raise ValueError("run_id must not be empty")
    if not timestamp or not timestamp.strip():
        raise ValueError("timestamp must not be empty")

    if isinstance(skills, Mapping):
        skill_records = tuple(
            sorted(
                (SkillRecord.from_content(name, content) for name, content in skills.items()),
                key=lambda record: record.name,
            )
        )
    else:
        skill_records = tuple(sorted(skills, key=lambda record: record.name))
        names = [record.name for record in skill_records]
        if len(names) != len(set(names)):
            raise ValueError(f"duplicate skill names in manifest input: {names}")

    tools_snapshot = ToolRegistrySnapshot.from_names(tool_names)
    pv_pairs = _pairs(package_versions)
    extra_pairs = _pairs(extra)

    manifest_hash = _compute_manifest_hash(
        system_prompt_hash=_hash_prefixed(system_prompt),
        skills=skill_records,
        tools=tools_snapshot,
        package_versions=pv_pairs,
        extra=extra_pairs,
    )

    return RunManifest(
        run_id=run_id,
        timestamp=timestamp,
        system_prompt_hash=_hash_prefixed(system_prompt),
        skills=skill_records,

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Dedupe by name before calling, keeping the intended version (e.g. last-loaded wins)
  2. If skills come from directories, detect collisions at load time rather than manifest time
  3. Pass a Mapping keyed by skill name so duplication is structurally impossible

Example fix

# before
skills = list(dir_a_skills) + list(dir_b_skills)  # both contain "deploy"
build_run_manifest(..., skills=skills)
# after
merged = {s.name: s for s in [*dir_a_skills, *dir_b_skills]}
build_run_manifest(..., skills=merged)
Defensive patterns

Strategy: validation

Validate before calling

skills_map = {}
for s in skills:
    skills_map[s.name] = s  # last wins; or detect and raise with context
names = [s.name for s in skills]
assert len(names) == len(set(names)), sorted({n for n in names if names.count(n) > 1})

Type guard

def has_unique_skill_names(skills: list) -> bool:
    names = [s.name for s in skills]
    return len(names) == len(set(names))

Try / catch

except ValueError as e: if 'duplicate skill names' in str(e): dedupe by name (decide precedence) and retry

Prevention

When it happens

Trigger: Calling build_run_manifest(skills=[SkillRecord(name="x",...), SkillRecord(name="x",...)]) with the same name appearing twice.

Common situations: Concatenating skill lists from multiple sources without deduping; case/normalization differences in generated names; tests seeding overlapping skill sets.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/3cf0aad640b6fc18. Report an issue: GitHub.