agentscope-ai/agentscope · error · ValueError
Bot {platform_bot_id!r} already drives channel {holder!r}.
Error message
Bot {platform_bot_id!r} already drives channel {holder!r}. What it means
Raised by SQLStorage.upsert_channel when the platform_bot_id is already bound to a different channel. One platform bot may drive only one channel, so the mapping platform_bot_id -> channel must stay unique.
Source
Thrown at src/agentscope/app/storage/_sql/_storage.py:1376
MySQL's ``ON DUPLICATE KEY UPDATE`` fires on *any*
unique-key conflict — the write would silently overwrite
the holder instead of failing, and the same call would
behave differently per dialect.
Neither this check nor `ChannelService.create`'s is
atomic with the write, so two creates racing for one bot
can both pass. The constraint then decides, and how it
surfaces depends on the dialect: Postgres and SQLite
raise `IntegrityError`, while on MySQL the duplicate-key
update lands on the holder's row and the read-back of
the new id then raises `NoResultFound`, rolling the
transaction back. Either way nothing is committed.
"""
holder = await self.get_channel_id_by_platform_bot_id(
platform_bot_id,
)
if holder is not None and holder != record.id:
raise ValueError(
f"Bot {platform_bot_id!r} already drives channel "
f"{holder!r}.",
)
await self._write_row(
ChannelRow,
record,
extra={"platform_bot_id": platform_bot_id},
)
return record.id
async def get_channel(self, channel_id: str) -> ChannelRecord | None:
"""Fetch a channel record by its global id.
Args:
channel_id (`str`):
The channel id.
Returns:View on GitHub (pinned to e90f1c7592)
Solutions
- Delete or re-point the existing channel that currently holds this platform_bot_id before upserting
- Use a distinct platform bot id per channel
- Update the existing channel record in place (same id) rather than creating a new one
Example fix
// before
await storage.upsert_channel(ChannelRecord(id=new_id, platform_bot_id="bot-1"))
// after
holder = await storage.get_channel_id_by_platform_bot_id("bot-1")
if holder is not None:
await storage.delete_channel(holder)
await storage.upsert_channel(ChannelRecord(platform_bot_id="bot-1", ...)) Defensive patterns
Strategy: validation
Validate before calling
holder = await storage.get_channel_id_by_platform_bot_id(rec.platform_bot_id)\nif holder is not None and holder != rec.id:\n await storage.delete_channel(holder)
Try / catch
try:\n await storage.upsert_channel(rec)\nexcept ValueError as e:\n if \"already drives channel\" in str(e): rebind_bot(rec)\n else: raise
Prevention
- One bot token per channel; track bindings centrally
- Delete old channel records before rebinding bots
When it happens
Trigger: Calling upsert_channel with a record whose platform_bot_id is already registered to another channel id (holder != record.id).
Common situations: Re-registering a bot token for a new channel without deleting the old channel record; reusing bot credentials across multiple channels; multi-tenant configs sharing the same platform bot.
Related errors
- An MCP named {mcp_record.name!r} already exists for this use
- A skill named {skill_record.name!r} already exists for this
- {str(e)}
- Bot '{bot_id}' already registered as channel '{existing}'.
- Channel '{channel_id}' not found.
AI-assisted analysis of agentscope-ai/agentscope@e90f1c7592 (2026-08-28).
Data as JSON: /api/errors/5c2100b363df22ab.
Report an issue: GitHub.