zeroclaw-labs/zeroclaw · error · anyhow::Error
Source workspace matches current ZeroClaw workspace; refusin
Error message
Source workspace matches current ZeroClaw workspace; refusing self-migration
What it means
After confirming the source workspace exists, migrate_openclaw_memory compares it against config.data_dir (the current ZeroClaw data directory) with paths_equal and refuses to continue if they are the same. The guard exists because migration reads from the source and writes into ZeroClaw's store; when they are one directory the migration would read and rewrite its own output, corrupting data.
Source
Thrown at crates/zeroclaw-runtime/src/migration.rs:41
renamed_conflicts: usize,
}
pub async fn migrate_openclaw_memory(
config: &Config,
source_workspace: Option<PathBuf>,
dry_run: bool,
reindex: bool,
) -> Result<()> {
let source_workspace = resolve_openclaw_workspace(source_workspace)?;
if !source_workspace.exists() {
bail!(
"OpenClaw workspace not found at {}. Pass --source <path> if needed.",
source_workspace.display()
);
}
if paths_equal(&source_workspace, &config.data_dir) {
bail!("Source workspace matches current ZeroClaw workspace; refusing self-migration");
}
let mut stats = MigrationStats::default();
let entries = collect_source_entries(&source_workspace, &mut stats)?;
if entries.is_empty() {
println!(
"No importable memory found in {}",
source_workspace.display()
);
println!("Checked for: memory/brain.db, MEMORY.md, memory/*.md");
return Ok(());
}
if dry_run {
println!("🔎 Dry run: OpenClaw migration preview");
println!(" Source: {}", source_workspace.display().to_string());
println!(" Target: {}", config.data_dir.display().to_string());View on GitHub (pinned to 88bb9c8533)
Solutions
- Point --source at the original OpenClaw workspace, keeping it distinct from ZeroClaw's data dir
- Check the current data dir (zeroclaw config get data_dir or equivalent) and make sure the two paths differ
- If the data genuinely overlaps, move one workspace to a separate directory first, then re-run
- If you already manually merged data, skip migration — nothing left to import
Example fix
# before data_dir = "/home/user/.openclaw" # zeroclaw.toml zeroclaw migrate-memory --source /home/user/.openclaw # after data_dir = "/home/user/.zeroclaw" zeroclaw migrate-memory --source /home/user/.openclaw
Defensive patterns
Strategy: validation
Validate before calling
let src = resolve_openclaw_workspace(source_workspace.clone())?;
if paths_equal(&src, &config.data_dir) {
// refuse early with a targeted message; source and destination must be distinct stores
anyhow::bail!("source equals data_dir; refusing to migrate in place");
} Try / catch
Err(e) if e.to_string().contains("refusing self-migration") => {
// config error: separate the two workspaces, then re-run; never bypass
} Prevention
- Keep OpenClaw and ZeroClaw workspaces in separate directory trees
- Before migrating, print both resolved paths for the operator to eyeball
- Never point data_dir at the legacy workspace to 'adopt' it — migrate instead
When it happens
Trigger: Passing --source that resolves to the ZeroClaw data dir itself; config.data_dir changed to point at the old OpenClaw directory (e.g. to "adopt" it in place); symlinks or different spellings of the same path (paths_equal normalizes, so /a/b vs /a/./b still collide).
Common situations: Adopt in place" setups where users repoint data_dir at OpenClaw's folder and then run migration; container mounts that map both workspaces to the same volume; copy-pasting a tutorial's --source that happens to equal the install's data dir.
Related errors
- OpenClaw workspace not found at {}. Pass --source <path> if
- OpenClaw memories table found but no content-like column was
- Unable to allocate non-conflicting key for '{base}'
- purge_agent not supported by this memory backend
- QQ channel requires the `channel-qq` feature
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/7a9c3f04f53a9c7b.
Report an issue: GitHub.