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

  1. Delete or re-point the existing channel that currently holds this platform_bot_id before upserting
  2. Use a distinct platform bot id per channel
  3. 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

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


AI-assisted analysis of agentscope-ai/agentscope@e90f1c7592 (2026-08-28). Data as JSON: /api/errors/5c2100b363df22ab. Report an issue: GitHub.