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
- Pick a new, unique version string before calling add_tool_version
- Check existence first (get_tools with the same tool_id/version) and skip or update instead of inserting
- Catch this Exception and treat it as a duplicate if duplicate inserts are expected in your flow
- 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
- Always pass an explicit unique version; do not rely on the default const.DEF_VER
- Make registration idempotent: check-then-insert or catch duplicates
- Serialize concurrent registrations of the same tool_id
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
- ErrCode.TOOL_NOT_EXIST_ERR
- CREATE_BOT_FAILED
- UPDATE_BOT_FAILED
- NOTIFICATION_MARK_READ_FAILED
- NOTIFICATION_DELETE_FAILED
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)