{"record":{"id":"24ac12b28b72d0b7","repo":"agentscope-ai/agentscope","slug":"a-skill-named-skill-record-name-r-already-exists-24ac12","errorCode":null,"errorMessage":"A skill named {skill_record.name!r} already exists for this user.","messagePattern":"A skill named (.+?) already exists for this user\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/agentscope/app/storage/_sql/_storage.py","lineNumber":914,"sourceCode":"                    MCPRow.id == mcp_id,\n                    MCPRow.user_id == user_id,\n                ),\n            )\n            await sess.commit()\n        return result.rowcount > 0\n\n    async def upsert_skill(\n        self,\n        user_id: str,\n        skill_record: SkillRecord,\n    ) -> str:\n        \"\"\"Create or update an installed-skill record for *user_id*.\n\n        Same contract as :meth:`RedisStorage.upsert_skill`.\n        \"\"\"\n        holder = await self.get_skill_by_name(user_id, skill_record.name)\n        if holder is not None and holder.id != skill_record.id:\n            raise ValueError(\n                f\"A skill named {skill_record.name!r} already exists for \"\n                f\"this user.\",\n            )\n        skill_record.user_id = user_id\n        await self._write_row(SkillRow, skill_record)\n        return skill_record.id\n\n    async def list_skills(self, user_id: str) -> list[SkillRecord]:\n        \"\"\"Return every installed-skill record for *user_id*.\"\"\"\n        from sqlalchemy import select\n\n        async with self._session() as sess:\n            rows = (\n                (\n                    await sess.execute(\n                        select(SkillRow).where(SkillRow.user_id == user_id),\n                    )\n                )","sourceCodeStart":896,"sourceCodeEnd":932,"githubUrl":"https://github.com/agentscope-ai/agentscope/blob/e90f1c7592896cc95f6e5ee506194f533378247d/src/agentscope/app/storage/_sql/_storage.py#L896-L932","documentation":"Raised by SQLStorage.upsert_skill when a skill record's name is already owned by a different skill record for the same user. Skill names are unique per user; the guard compares the stored record's id to skill_record.id and rejects the write on mismatch.","triggerScenarios":"Calling upsert_skill(user_id, record) where record.name collides with another skill of that user and record.id is not the existing record's id.","commonSituations":"Installing a second skill with the same display name; reinstalling a skill after its record was recreated with a fresh id; syncing skills between machines without carrying ids.","solutions":["Rename the incoming skill to something unique for that user","Fetch the existing skill via get_skill_by_name and update it in place, preserving its id","Remove the old conflicting skill before installing the new one"],"exampleFix":"// before\nawait storage.upsert_skill(user_id, SkillRecord(id=fresh, name=\"search\"))\n// after\nold = await storage.get_skill_by_name(user_id, \"search\")\nif old:\n    await storage.delete_skill(user_id, old.id)\nawait storage.upsert_skill(user_id, SkillRecord(name=\"search\", ...))","handlingStrategy":"validation","validationCode":"if (dup := await storage.get_skill_by_name(user_id, rec.name)) and dup.id != rec.id:\\n    raise Exception(f\\\"skill name {rec.name!r} taken\\\")","typeGuard":null,"tryCatchPattern":"try:\\n    await storage.upsert_skill(user_id, rec)\\nexcept ValueError as e:\\n    if \\\"already exists\\\" in str(e): rename_or_merge(rec)\\n    else: raise","preventionTips":["Namespace skill names by source/package","Check get_skill_by_name before install flows"],"tags":["skills","unique-constraint","sql-storage","upsert"],"backgroundTag":"duplicate-record-name","analyzedSha":"e90f1c7592896cc95f6e5ee506194f533378247d","analyzedAt":"2026-08-28T18:24:12.087Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}