zeroclaw-labs/zeroclaw · error

cannot rename agent memory to `{to}`: an existing memory sto

Error message

cannot rename agent memory to `{to}`: an existing memory store under that alias has {to_rows} row(s); refusing to merge

What it means

PostgresMemory::rename_agent refuses to overwrite an existing agent's memory: inside a transaction it counts the destination alias's memory rows, and any row count > 0 aborts, because renaming would silently merge two memory stores irreversibly (the transaction would otherwise delete the empty destination agent row and re-point the source alias). The message reports the conflicting alias and row count.

Source

Thrown at crates/zeroclaw-memory/src/postgres.rs:640

        let client = self.client.get().clone();
        let qualified_agents = self.qualified_agents.clone();
        let qualified_table = self.qualified_table.clone();
        let from = from.to_string();
        let to = to.to_string();

        run_on_os_thread(move || -> Result<usize> {
            let mut client = client.lock();
            let mut tx = client.transaction()?;
            let to_rows: i64 = tx
                .query_one(
                    &format!(
                        "SELECT COUNT(*) FROM {qualified_table} WHERE agent_id = (SELECT id FROM {qualified_agents} WHERE alias = $1)"
                    ),
                    &[&to],
                )?
                .get(0);
            if to_rows > 0 {
                anyhow::bail!(
                    "cannot rename agent memory to `{to}`: an existing memory store under that alias has {to_rows} row(s); refusing to merge"
                );
            }
            tx.execute(
                &format!("DELETE FROM {qualified_agents} WHERE alias = $1"),
                &[&to],
            )?;
            let updated = tx.execute(
                &format!("UPDATE {qualified_agents} SET alias = $2 WHERE alias = $1"),
                &[&from, &to],
            )?;
            tx.commit()?;
            usize::try_from(updated).context("PostgreSQL returned an oversized update count")
        })
        .await
    }

    async fn count_agent(&self, agent_alias: &str) -> Result<usize> {

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Pick a destination alias that does not exist or holds no memory rows.
  2. If the target data is disposable, purge it first (purge_agent on the target alias), then retry the rename.
  3. If both stores must survive, export_agent both aliases before renaming so nothing is lost.

Example fix

// before
memory.rename_agent("old-name", "writer").await?; // writer already has 42 rows

// after
let target = memory.export_agent("writer").await?;
if !target.is_empty() {
    memory.purge_agent("writer").await?; // only if disposable
}
memory.rename_agent("old-name", "writer").await?;
Defensive patterns

Strategy: validation

Validate before calling

// rename_agent refuses a non-empty target; check the same condition first
let target_rows = memory.export_agent(to).await?;
if !target_rows.is_empty() {
    anyhow::bail!(
        "target alias '{to}' already holds {} memory row(s); \
         purge or pick another name",
        target_rows.len()
    );
}
memory.rename_agent(from, to).await?;

Try / catch

match memory.rename_agent(from, to).await {
    Ok(n) => Ok(n),
    Err(e) if e.to_string().contains("refusing to merge") => {
        // decide policy: pick another alias, or purge the target after backup
        Err(e.context("rename target occupied; export/purge it first"))
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Calling rename_agent(from, to) when the destination alias `to` exists in the agents table and already owns at least one memory row — e.g. renaming to a retired agent's name that still has data.

Common situations: Reusing old agent names after reorganizations; retrying a rename after an earlier partial/manual attempt left rows; renaming onto an alias that a test or another agent populated.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/688453c3e632e296. Report an issue: GitHub.