hermes - ✅(Solved) Fix [claw migrate] Migration fails with "are the same file" when source workspace contains symlinks [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#24943Fetched 2026-05-14 03:50:25
View on GitHub
Comments
0
Participants
1
Timeline
5
Reactions
0
Author
Participants
Timeline (top)
labeled ×3cross-referenced ×1referenced ×1

hermes claw migrate fails near the end of execution with a shutil.copy() error when the source OpenClaw workspace contains symlinks pointing to files outside the workspace. The migration applies ~32 items correctly (memories, SOUL, USER, skills, secrets, providers, config) and then aborts during what appears to be a final workspace asset copy step that wasn't shown in the dry-run preview.

Error Message

hermes claw migrate fails near the end of execution with a shutil.copy() error when the source OpenClaw workspace contains symlinks pointing to files outside the workspace. The migration applies ~32 items correctly (memories, SOUL, USER, skills, secrets, providers, config) and then aborts during what appears to be a final workspace asset copy step that wasn't shown in the dry-run preview. 7. Migration aborts with the error below.

Error output

Python's shutil.copy() raises SameFileError when source and destination resolve to the same inode. The error message shows identical source and destination paths, which suggests the migration script either: The traceback isn't shown in the CLI output, so I cannot confirm which code path produces the duplicate paths.

Root Cause

  • The ~32 items applied before the abort remain in place; partial success is recoverable.
  • The auto-backup zip allows full rollback via hermes import.
  • For my case the impact is low because the physical IDENTITY.md already exists in the workspace and Hermes accesses it via the terminal.cwd config. Other users with stricter expectations of workspace materialization in ~/.hermes/ could lose more.

Fix Action

Workaround

For users hitting this: the migration already applied everything important (memories, SOUL, USER, skills, secrets, providers, config). The IDENTITY.md and other workspace files can be referenced directly via terminal.cwd in config.yaml pointing to the original workspace, no copy needed.

PR fix notes

PR #24956: fix(migration): handle symlinks and SameFileError in claw migrate workspace copy

Description (problem / solution / changelog)

Summary

Fixes #24943 — hermes claw migrate fails with shutil.SameFileError when the source OpenClaw workspace contains symlinks that resolve to the same file as the migration destination.

Root Cause

When the source workspace has symlinks (e.g., IDENTITY.md → ../OpenClaw-Workspace/IDENTITY.md) and the migration's resolved source_root causes the symlink target to match the destination path, shutil.copy2() raises SameFileError: '...' and '...' are the same file.

Additionally, copy_tree_non_destructive follows symlinks during rglob("*"), which can include symlinked files that should be skipped during workspace migration.

Fix

Three changes in openclaw_to_hermes.py:

  1. Skip symlinks in file collectioncopy_tree_non_destructive now filters out symlinks with not p.is_symlink() in the rglob comprehension
  2. Catch SameFileError in copy_tree_non_destructive — wraps shutil.copy2() in try/except, treating same-file as skipped
  3. Catch SameFileError in copy_file — wraps shutil.copy2() in try/except, recording as skipped with descriptive reason

Regression Coverage

3 new tests in tests/skills/test_openclaw_migration.py:

  • test_copy_tree_non_destructive_skips_symlinks — verifies symlinks are excluded from file collection
  • test_copy_tree_non_destructive_handles_same_file_error — verifies graceful handling when source and dest are the same file
  • test_copy_file_handles_same_file_error — verifies copy_file handles hardlinked source/dest without crashing

Testing

44 passed in 2.63s (full migration test suite)

Fixes [claw migrate] Migration fails with "are the same file" when source workspace contains symlinks #24943

Changed files

  • optional-skills/migration/openclaw-migration/scripts/openclaw_to_hermes.py (modified, +11/-3)
  • tests/skills/test_openclaw_migration.py (modified, +111/-0)
RAW_BUFFERClick to expand / collapse

Summary

hermes claw migrate fails near the end of execution with a shutil.copy() error when the source OpenClaw workspace contains symlinks pointing to files outside the workspace. The migration applies ~32 items correctly (memories, SOUL, USER, skills, secrets, providers, config) and then aborts during what appears to be a final workspace asset copy step that wasn't shown in the dry-run preview.

Environment

  • Hermes Agent v0.13.0 (2026.5.7) "Tenacity"
  • macOS 26 (arm64, Apple Silicon)
  • Installed via official scripts/install.sh
  • Python 3.11.15 in ~/.hermes/hermes-agent/venv

Reproduction

  1. OpenClaw installation at ~/.openclaw-myagent/ with a workspace at ~/OpenClaw-Workspace-myagent/ that contains a mix of physical files and symlinks (e.g. BRIEFING.md../OpenClaw-Workspace/BRIEFING.md, MEMORY-global.md../OpenClaw-Workspace/MEMORY-global.md, etc.). Physical files include IDENTITY.md, AGENTS.md, and others.

  2. Run dry-run preview first — completes successfully:

    hermes claw migrate --source ~/.openclaw-myagent/ --dry-run --preset full --migrate-secrets

    Output: 31 would migrate, 2 conflict(s), 19 skipped. Workspace items appear under "Skipped: workspace-agents — No workspace target was provided".

  3. Run real migration with --overwrite:

    hermes claw migrate --source ~/.openclaw-myagent/ --preset full --migrate-secrets --overwrite
  4. Preview shows 33 would migrate, 0 skipped. User confirms.

  5. Auto-backup zip is written to ~/.hermes/backups/.

  6. ~32 items apply correctly to ~/.hermes/ (verifiable by ls ~/.hermes/memories/, ~/.hermes/skills/openclaw-imports/, etc.).

  7. Migration aborts with the error below.

Error output

✓ Pre-migration backup: /Users/USER/.hermes/backups/pre-migration-2026-05-13-093752.zip (2.3 MB)
  Restore with: hermes import pre-migration-2026-05-13-093752.zip

✗ Migration failed: PosixPath('/Users/USER/OpenClaw-Workspace-myagent/IDENTITY.md') and PosixPath('/Users/USER/OpenClaw-Workspace-myagent/IDENTITY.md') are the same file
  A pre-migration backup is available at: /Users/USER/.hermes/backups/pre-migration-2026-05-13-093752.zip
  Restore with: hermes import pre-migration-2026-05-13-093752.zip

Probable cause

Python's shutil.copy() raises SameFileError when source and destination resolve to the same inode. The error message shows identical source and destination paths, which suggests the migration script either:

  • Resolved the workspace destination to the source workspace itself (no --workspace-target was provided, so it may have defaulted to the source path), or
  • Followed a symlink during workspace traversal, resolved to the same physical file, and attempted to copy it back to itself.

The traceback isn't shown in the CLI output, so I cannot confirm which code path produces the duplicate paths.

Inconsistency with dry-run

The dry-run reported workspace-agents — Skipped: No workspace target was provided. The non-dry-run execution attempted to copy a workspace file regardless of that decision, suggesting different code paths between preview and apply for the workspace assets stage.

Impact

  • The ~32 items applied before the abort remain in place; partial success is recoverable.
  • The auto-backup zip allows full rollback via hermes import.
  • For my case the impact is low because the physical IDENTITY.md already exists in the workspace and Hermes accesses it via the terminal.cwd config. Other users with stricter expectations of workspace materialization in ~/.hermes/ could lose more.

Suggested fix

In the workspace copy step:

  1. If source and destination resolve to the same inode, skip silently (with debug log) instead of raising.
  2. If no --workspace-target is provided, either skip the workspace copy step entirely (matching the dry-run behavior) or fail fast before any items are applied so users don't end up with partial migrations.
  3. Make the preview consistent with apply for the workspace stage.

Workaround

For users hitting this: the migration already applied everything important (memories, SOUL, USER, skills, secrets, providers, config). The IDENTITY.md and other workspace files can be referenced directly via terminal.cwd in config.yaml pointing to the original workspace, no copy needed.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING