{"record":{"id":"688453c3e632e296","repo":"zeroclaw-labs/zeroclaw","slug":"cannot-rename-agent-memory-to-to-an-existing","errorCode":null,"errorMessage":"cannot rename agent memory to `{to}`: an existing memory store under that alias has {to_rows} row(s); refusing to merge","messagePattern":"cannot rename agent memory to `(.+?)`: an existing memory store under that alias has (.+?) row\\(s\\); refusing to merge","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-memory/src/postgres.rs","lineNumber":640,"sourceCode":"        let client = self.client.get().clone();\n        let qualified_agents = self.qualified_agents.clone();\n        let qualified_table = self.qualified_table.clone();\n        let from = from.to_string();\n        let to = to.to_string();\n\n        run_on_os_thread(move || -> Result<usize> {\n            let mut client = client.lock();\n            let mut tx = client.transaction()?;\n            let to_rows: i64 = tx\n                .query_one(\n                    &format!(\n                        \"SELECT COUNT(*) FROM {qualified_table} WHERE agent_id = (SELECT id FROM {qualified_agents} WHERE alias = $1)\"\n                    ),\n                    &[&to],\n                )?\n                .get(0);\n            if to_rows > 0 {\n                anyhow::bail!(\n                    \"cannot rename agent memory to `{to}`: an existing memory store under that alias has {to_rows} row(s); refusing to merge\"\n                );\n            }\n            tx.execute(\n                &format!(\"DELETE FROM {qualified_agents} WHERE alias = $1\"),\n                &[&to],\n            )?;\n            let updated = tx.execute(\n                &format!(\"UPDATE {qualified_agents} SET alias = $2 WHERE alias = $1\"),\n                &[&from, &to],\n            )?;\n            tx.commit()?;\n            usize::try_from(updated).context(\"PostgreSQL returned an oversized update count\")\n        })\n        .await\n    }\n\n    async fn count_agent(&self, agent_alias: &str) -> Result<usize> {","sourceCodeStart":622,"sourceCodeEnd":658,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-memory/src/postgres.rs#L622-L658","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pick a destination alias that does not exist or holds no memory rows.","If the target data is disposable, purge it first (purge_agent on the target alias), then retry the rename.","If both stores must survive, export_agent both aliases before renaming so nothing is lost."],"exampleFix":"// before\nmemory.rename_agent(\"old-name\", \"writer\").await?; // writer already has 42 rows\n\n// after\nlet target = memory.export_agent(\"writer\").await?;\nif !target.is_empty() {\n    memory.purge_agent(\"writer\").await?; // only if disposable\n}\nmemory.rename_agent(\"old-name\", \"writer\").await?;","handlingStrategy":"validation","validationCode":"// rename_agent refuses a non-empty target; check the same condition first\nlet target_rows = memory.export_agent(to).await?;\nif !target_rows.is_empty() {\n    anyhow::bail!(\n        \"target alias '{to}' already holds {} memory row(s); \\\n         purge or pick another name\",\n        target_rows.len()\n    );\n}\nmemory.rename_agent(from, to).await?;","typeGuard":null,"tryCatchPattern":"match memory.rename_agent(from, to).await {\n    Ok(n) => Ok(n),\n    Err(e) if e.to_string().contains(\"refusing to merge\") => {\n        // decide policy: pick another alias, or purge the target after backup\n        Err(e.context(\"rename target occupied; export/purge it first\"))\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Check the destination alias with export_agent/count_agent before offering a rename in tooling — refuse occupied names in the UI.","Back up both stores (export_agent) before any rename so a refused or mistaken merge attempt is always recoverable."],"tags":["postgres","rename","conflict","agent-management","data-safety"],"backgroundTag":"rename-target-conflict","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}