iflytek/astron-agent · error · Exception

Version already exists!

Error message

Version already exists!

What it means

add_tool_version inserts a new Tools row whose unique constraint covers (tool_id, version). When a row with the same tool_id and version already exists, the database driver raises IntegrityError on commit; the code rolls back and re-raises a plain Exception with 'Version already exists!'. It means you are trying to register a version that is already registered.

Solutions

  1. Pick a new, unique version string before calling add_tool_version
  2. Check existence first (get_tools with the same tool_id/version) and skip or update instead of inserting
  3. Catch this Exception and treat it as a duplicate if duplicate inserts are expected in your flow
  4. Remove the conflicting row (delete_tools) if the old version should be replaced

Example fix

# before
process.add_tool_version([{"tool_id": tid, "app_id": aid, "name": n}])  # defaults to DEF_VER, collides
# after
version = "1.0.1"
if not process.get_tools([{"tool_id": tid, "version": version}], span):
    process.add_tool_version([{"tool_id": tid, "app_id": aid, "name": n, "version": version}])
Defensive patterns

Strategy: try-catch

Validate before calling

existing = process.get_tools([{"tool_id": tid, "version": ver}], span)
if existing:
    process.update_tools([{...}])  # update instead of insert
else:
    process.add_tool_version([{...}])

Type guard

def is_new_version(tool: dict, existing_versions: set) -> bool:
    return tool.get("version", const.DEF_VER) not in existing_versions

Try / catch

try:
    process.add_tool_version(tools)
except Exception as e:
    if "Version already exists" in str(e):
        logger.warning(f"duplicate version, skipping: {tools}")
    else:
        raise

Prevention

When it happens

Trigger: Calling add_tool_version with a dict whose (tool_id, version) pair already exists in the tools table — e.g. omitting 'version' so it defaults to const.DEF_VER when a default-version row already exists, or re-submitting the same tool registration twice.

Common situations: Idempotency mistakes: retrying a registration after a timeout, omitting the version field so it collides with the default version, or a concurrent writer inserting the same version first.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12). Data as JSON: /api/errors/78246b0f08a57c55. Report an issue: GitHub.

Appendix: source

Thrown at core/plugin/link/infra/tool_crud/process.py:146

        description: Add tool version
        """
        with session_getter(self.engine) as session:
            for tool in tool_info:
                try:
                    tool_inst = Tools(
                        app_id=tool.get("app_id"),
                        tool_id=tool.get("tool_id"),
                        name=tool.get("name"),
                        description=tool.get("description"),
                        open_api_schema=tool.get("open_api_schema"),
                        version=tool.get("version", const.DEF_VER),
                        is_deleted=tool.get("is_deleted", const.DEF_DEL),
                    )
                    session.add(tool_inst)
                    session.commit()
                except IntegrityError as e:
                    session.rollback()
                    raise Exception("Version already exists!") from e

    def delete_tools(self, tool_info: List[Dict[str, Any]]) -> None:
        """
        description: Delete tools
        """
        with session_getter(self.engine) as session:
            for tool in tool_info:
                tool_id = tool.get("tool_id", "")
                version = (tool.get("version", ""),)
                if isinstance(version, tuple):
                    # If it's a tuple, take the first element
                    version = version[0]

                is_deleted = tool.get("is_deleted", const.DEF_DEL)
                if version:
                    query = (
                        select(Tools)
                        .where(

View on GitHub (pinned to 5e758547a8)