hermes - 💡(How to fix) Fix `hermes skills install` crashes with OSError when install destination is a symlink

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…

hermes skills install fails with an unhandled OSError when the install destination at ~/.hermes/skills/<skill-name> already exists as a symbolic link. install_from_quarantine calls shutil.rmtree(install_dir) without first checking whether install_dir is a symlink, and Python's shutil.rmtree refuses to operate on symlinks by design.

Error Message

Unhandled exception bubbles up to the user. Skill is not installed. Quarantine state is left behind:

  • A clear, user-facing error message explains the symlink at <path> is blocking installation and suggests rm <path> to resolve, instead of an unhandled traceback. P3 / Low. Workaround is straightforward once the symlink is identified, but the unhandled traceback presents poorly to new users and obscures the actual cause. Fix is a 4-line change.

Root Cause

hermes skills install fails with an unhandled OSError when the install destination at ~/.hermes/skills/<skill-name> already exists as a symbolic link. install_from_quarantine calls shutil.rmtree(install_dir) without first checking whether install_dir is a symlink, and Python's shutil.rmtree refuses to operate on symlinks by design.

Fix Action

Workaround

Manually remove the symlink, then retry: rm -f ~/.hermes/skills/<skill-name> hermes skills install <identifier> --force

Code Example

import os, shutil

if os.path.islink(install_dir):
    os.unlink(install_dir)
elif os.path.isdir(install_dir):
    shutil.rmtree(install_dir)
RAW_BUFFERClick to expand / collapse

Summary

hermes skills install fails with an unhandled OSError when the install destination at ~/.hermes/skills/<skill-name> already exists as a symbolic link. install_from_quarantine calls shutil.rmtree(install_dir) without first checking whether install_dir is a symlink, and Python's shutil.rmtree refuses to operate on symlinks by design.

Environment

  • Hermes version: v0.13.0 (2026.5.7)
  • Python: 3.9.6
  • OS: macOS (Apple Intel: MacBook Pro 2019)
  • Install path: ~/.hermes/hermes-agent/

Steps to reproduce

  1. Attempt to install a hub skill (any skill, any source) where the install destination already exists as a symlink rather than a directory: hermes skills install skills-sh/browserbase/skills/autobrowse --force
  2. The fetch and security scan complete successfully.
  3. install_from_quarantine then attempts to clean the destination and crashes.

*Note: may have impacted the installation: hermes skills install skills-sh/firecrawl/cli/firecrawl --force and added symlink globally

Actual behavior

Unhandled exception bubbles up to the user. Skill is not installed. Quarantine state is left behind: File "/Users/<user>/.hermes/hermes-agent/hermes_cli/main.py", line 10926, in main args.func(args) File "/Users/<user>/.hermes/hermes-agent/hermes_cli/main.py", line 9723, in cmd_skills skills_command(args) File "/Users/<user>/.hermes/hermes-agent/hermes_cli/skills_hub.py", line 1325, in skills_command do_install(args.identifier, category=args.category, force=args.force, ...) File "/Users/<user>/.hermes/hermes-agent/hermes_cli/skills_hub.py", line 603, in do_install install_dir = install_from_quarantine(q_path, bundle.name, category, bundle, result) File "/Users/<user>/.hermes/hermes-agent/tools/skills_hub.py", line 2739, in install_from_quarantine shutil.rmtree(install_dir) File ".../python3.11/shutil.py", line 767, in rmtree raise OSError("Cannot call rmtree on a symbolic link") OSError: Cannot call rmtree on a symbolic link

Expected behavior

Either:

  • Install proceeds successfully by detecting and unlinking the symlink before placing the new directory, or
  • A clear, user-facing error message explains the symlink at <path> is blocking installation and suggests rm <path> to resolve, instead of an unhandled traceback.

Workaround

Manually remove the symlink, then retry: rm -f ~/.hermes/skills/<skill-name> hermes skills install <identifier> --force

Suggested fix

In tools/skills_hub.py at the install_from_quarantine function, around line 2739, replace the unconditional shutil.rmtree(install_dir) with a symlink-aware cleanup:

import os, shutil

if os.path.islink(install_dir):
    os.unlink(install_dir)
elif os.path.isdir(install_dir):
    shutil.rmtree(install_dir)

This handles both the directory case (current behavior) and the symlink case (currently crashes), and is the standard Python idiom for "remove whatever is at this path."

Severity

P3 / Low. Workaround is straightforward once the symlink is identified, but the unhandled traceback presents poorly to new users and obscures the actual cause. Fix is a 4-line change.

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…

FAQ

Expected behavior

Either:

  • Install proceeds successfully by detecting and unlinking the symlink before placing the new directory, or
  • A clear, user-facing error message explains the symlink at <path> is blocking installation and suggests rm <path> to resolve, instead of an unhandled traceback.

Still need to ship something?

×6

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

Back to top recommendations

TRENDING