English | 中文
Fix "path too long" for good — before or after it bites:
longpath scan— find every path that breaks the Windows 260-character MAX_PATH limit, or simulate a copy into a deep destination folder before you hit "Destination Path Too Long"longpath check— lint a repo/folder for names that break Windows & macOS: reserved names (CON,NUL, …), illegal characters, trailing dots, case collisions, over-long paths. CI-friendly exit codeslongpath why— explain where one path's budget went, component by component, with rename suggestionslongpath rm— delete the trees that Explorer,del,rmdirandshutil.rmtreerefuse to delete — including files namedconor ending in a dot
Pure Python standard library. Zero dependencies. Works on Windows, Linux and macOS. Not on PyPI yet:
pip install git+https://github.com/hc-ui/longpath.gitSame toolbox: whoseport · wholocks · eoldoctor
❌ Destination Path Too Long — The file name(s) would be too long for the destination folder.
❌ The source file name(s) are larger than is supported by the file system.
❌
error: invalid path 'aux.md'/error: unable to create file ... Filename too long— duringgit cloneon Windows
❌
PermissionError: [WinError 206] The filename or extension is too long
❌ Cannot delete
node_modules— the path is too long, and the folk remedy is a weirdrobocopy /MIRtrick
Windows still ships with a 260-character path budget. You usually discover this after the copy died at 87%, the backup silently skipped files, or a colleague on Windows can't clone the repo you made on Linux. longpath finds these landmines up front, and cleans up the wreckage when it's too late.
# what in this tree already breaks the 260-char limit?
longpath scan D:\projects
# PRE-FLIGHT: will copying this folder into that deep OneDrive dir break?
longpath scan .\thesis --base "C:\Users\me\OneDrive - University\Documents\FinalWork"
# lint this repo for Windows-breaking names (great in CI)
longpath check .
# where exactly did those 300 characters go, and what should I rename?
longpath why "D:\deep\path\from\the\scan\report.txt"
# delete what Explorer refuses to delete
longpath rm D:\stuck\node_modules$ longpath scan D:\data
longpath scan D:\data
budget: 259 usable chars (limit 260)
scanned: 12,304 files, 1,201 dirs deepest nesting: 14
longest: 312 chars D:\data\projects\archive\2024\group-final\node_modules\...\index.d.ts
3 paths exceed the budget (worst is 53 chars over):
+53 312 D:\data\projects\archive\2024\group-final\node_modules\@typescript-eslint\...\index.d.ts
+21 280 D:\data\projects\archive\2024\group-final\node_modules\.cache\babel-loader\...
+2 261 DIR D:\data\backup\photos\2023 holiday trip with the whole family\raw exports\selected
Windows long-path policy: DISABLED - Explorer, cmd and most apps stop at 260 chars
enable (admin): reg add "HKLM\SYSTEM\CurrentControlSet\Control\FileSystem" /v LongPathsEnabled /t REG_DWORD /d 1 /f
hints: fix by shortening the deepest folders; delete stuck trees with 'longpath rm <path>'; preview a copy with '--base DEST'
The killer feature nothing else does: measure your tree as if it were copied into a destination, so "Destination Path Too Long" never surprises you again. Works for OneDrive/SharePoint sync folders (which add their own long prefixes), USB hand-offs, zip extraction targets, NAS moves.
$ longpath scan .\thesis --base "C:\Users\student\OneDrive - University\Documents\Course Materials\Final"
longpath scan D:\work\thesis
budget: 259 usable chars (limit 260) simulating copy into: C:\Users\student\OneDrive - University\...
scanned: 214 files, 37 dirs deepest nesting: 6
7 paths exceed the budget (worst is 44 chars over):
+44 303 C:\Users\student\OneDrive - University\...\thesis\data\interviews\transcripts\...
...
Exit code is 1 when anything would break — perfect for a pre-copy check in scripts.
Made on Linux/macOS, broken on Windows: reserved device names, : in filenames, names ending with a dot, README.md vs readme.md in one directory. These make git clone fail or silently produce wrong files on other people's machines. Run longpath check . in CI and never ship one again.
$ longpath check .
longpath check /home/me/my-repo
6 issue(s) in 3,456 paths
[reserved-name] (1)
/home/me/my-repo/docs/aux.md
'aux.md' is a reserved DOS device name on Windows (AUX); Windows cannot create it and git clone fails with 'invalid path'
[illegal-char] (2)
/home/me/my-repo/notes/plan:v2.txt
'plan:v2.txt' contains characters illegal on Windows: :
[case-collision] (1)
/home/me/my-repo/src
'Utils.py', 'utils.py' differ only by letter case; they collide on the case-insensitive filesystems of Windows/macOS and git checkout silently overwrites one with the other
...
Rules: too-long · reserved-name · illegal-char · trailing-dot-space · case-collision · unicode-collision · component-too-long · undecodable-name — suppress any with --ignore, skip vendored folders with --exclude.
$ longpath why "D:\demo\an example folder with a long name\...\node_modules\@example-scope\some-package-name\dist\rules\index.d.ts"
longpath why D:\demo\an example folder with a long name\...\index.d.ts
218 chars - fits the 259-char budget with 41 to spare
cum len component
3 3 D:\
7 4 demo
42 34 an example folder with a long name
68 25 another nested level here
...
218 10 index.d.ts
biggest wins (rename these):
'an example folder with a long name' (34 chars) -> saves up to 33
'deeply nested subfolder name' (28 chars) -> saves up to 27
The path does not need to exist — paste a Windows path out of a log or a CI failure on your Linux box and analyse it there. When a path is over budget, the exact component that crosses the line gets marked.
$ longpath rm D:\stuck\node_modules
Delete D:\stuck\node_modules? This cannot be undone. [y/N] y
deleted: D:\stuck\node_modules (48,211 files, 6,890 dirs)
- handles paths far beyond 260 chars (extended-length
\\?\API paths — no registry change, no reboot) - deletes cursed names that Explorer and
delcannot touch: files literally namedcon/aux.txt, or ending in a dot or space (git, WSL and 7-Zip can all drop these onto NTFS) - clears the read-only attribute when it blocks deletion
- never follows symlinks or junctions — only the link is removed, the target survives (this is the mistake that turns "clean a temp folder" into "wipe your user profile")
- refuses to delete filesystem roots;
--dry-runpreviews; keeps going on errors and reports every failure
| pip install, everywhere | Windows | Linux/macOS | Find/scan before copying | Repo lint (CI) | Delete >260 trees | Zero deps | Python API | |
|---|---|---|---|---|---|---|---|---|
| longpath | ✅ | ✅ | ✅ | ✅ --base pre-flight |
✅ 8 rules | ✅ | ✅ | ✅ |
| SuperDelete (C#) | ❌ download .exe | ✅ | ❌ | ❌ | ❌ | ✅ | – | ❌ |
| winrmrf (Nim, 2017) | ❌ download .exe | ✅ | ❌ | ❌ | ❌ | ✅ | – | ❌ |
robocopy /MIR empty-dir trick |
built-in | ✅ | ❌ | ❌ | ❌ | ✅ arcane, destructive if mistyped | – | ❌ |
PowerShell \\?\ + Remove-Item |
built-in | ✅ | ❌ | ❌ | ❌ | – | ❌ | |
| "Long Path Tool" | ❌ | ✅ | ❌ | ❌ | ❌ | 💰 nagware that monetises this exact search query | – | ❌ |
Enabling LongPathsEnabled |
– | – | ❌ | ❌ | – | – | ||
git core.protectNTFS |
– | ✅ | – | ❌ | – | – | – |
Things almost every blog post gets subtly wrong — longpath gets them right:
MAX_PATHis 260, but the budget is 259 — the count includes a terminatingNUL. A 260-char path already fails. (Directories effectively get ~248, because Windows reserves room for an 8.3 filename.)- The limit counts UTF-16 code units, not "characters". An emoji or any non-BMP character costs 2 units.
longpathmeasureslen(path.encode('utf-16-le'))//2, notlen(path)— so 中文 counts 1 per char, 😀 counts 2. LongPathsEnabledis not a fix. It lifts the limit only for applications that declarelongPathAwarein their manifest. Explorer, most installers and plenty of tools still fail. That's whyscantells you the policy state but treats 260 as the real-world budget.\\?\extended-length paths bypass the limit entirely (up to ~32,767 units).longpath rmand the scanner use them internally, which is also how the scanner can even see paths that other tools cannot traverse.- Junctions and symlinks are landmines during deletion.
longpathdetects reparse points and removes the link, never the target — and its test suite proves it with real junctions. - OneDrive/SharePoint have their own ~400-char ceilings that include the sync-root prefix. Model them with
--limit 400 --base "<your sync folder>".
from longpath import scan_tree, check_tree, rm_path, why_path
result = scan_tree(r"D:\projects") # what's over MAX_PATH?
for p in result.over:
print(p.over, p.path)
result = scan_tree("thesis", base=r"C:\Users\me\OneDrive\Documents") # pre-flight
issues, stats = check_tree(".", ignore={"too-long"}, exclude=["node_modules"])
outcome = rm_path(r"D:\stuck\node_modules") # delete the undeletable
print(outcome.ok, outcome.files_removed, outcome.errors)
breakdown = why_path(r"C:\some\very\deep\path.txt") # budget breakdownlongpath scan [DIR] [--limit N] [--base DEST] [--top N] [--all] [--exclude GLOB] [--json] [-q]
longpath check [DIR] [--limit N] [--base DEST] [--ignore RULES] [--exclude GLOB] [--json] [-q]
longpath why PATH [--limit N] [--json] [-q]
longpath rm PATH... [-y] [-n/--dry-run] [--json] [-q]
longpath <dir> is shorthand for longpath scan <dir>. Exit codes: 0 clean · 1 findings · 2 error — so both scan and check drop straight into CI:
- run: pip install git+https://github.com/hc-ui/longpath.git && longpath check .Do I need admin rights? No. Everything works as a normal user (only enabling the long-path policy needs admin, and that's a suggestion longpath prints, not something it does).
Why can't Explorer delete these folders anyway? Explorer isn't long-path aware even with the policy enabled. longpath rm talks to the filesystem with \\?\ extended-length paths, which have worked since Windows XP.
I'm on Linux/macOS — why would I care? Because your users are on Windows. longpath check in CI catches the aux.md file or the Utils.py/utils.py pair before they break git clone for half your team. It also pre-flights copies to NAS/USB/network shares.
Is it safe? rm never follows links (junction/symlink targets survive), refuses filesystem roots, has --dry-run, and requires -y in non-interactive use. The scanner is read-only.
What Python versions? 3.9 – 3.14, CPython, no dependencies at all.
MIT © hc-ui
English | 中文
一条命令根治**"路径太长"**——事前预防,事后救援:
longpath scan—— 找出所有超过 Windows 260 字符 MAX_PATH 限制的路径;还能预演复制:先算一遍"拷进那个很深的目标文件夹会不会爆",再动手longpath check—— 给仓库/文件夹做 Windows/macOS 兼容性体检:保留名(CON、NUL…)、非法字符、结尾句点、大小写冲突、超长路径,退出码适配 CIlongpath why—— 逐层拆解一条路径的长度预算花在哪,给出"改哪个文件夹名收益最大"longpath rm—— 删除资源管理器、del、rmdir、shutil.rmtree都删不掉的目录树,包括文件名叫con、结尾带句点这类"魔鬼文件"
纯 Python 标准库,零依赖。尚未上 PyPI:
pip install git+https://github.com/hc-ui/longpath.git❌ 目标路径太长 —— 文件名对目标文件夹可能过长。
❌ 源文件名长度大于文件系统支持的长度。
❌ Windows 上
git clone报error: invalid path 'aux.md'或Filename too long
❌
PermissionError: [WinError 206] 文件名或扩展名太长
❌
node_modules删不掉,网上教你用robocopy /MIR空目录镜像这种偏方
Windows 至今默认带着 260 字符的路径预算。你往往在复制到 87% 失败、备份悄悄漏文件、或者 Windows 同学克隆不了你在 Linux 上建的仓库时,才发现踩了雷。longpath 把雷提前找出来;真炸了,也能收拾残局。
# 这棵目录树里,哪些路径已经超 260 了?
longpath scan D:\资料
# 预演:把论文文件夹拷进 OneDrive 深层目录,会不会爆?
longpath scan .\毕业论文 --base "C:\Users\me\OneDrive - 学校\文档\最终版"
# 给仓库做兼容性体检(CI 必备)
longpath check .
# 这条 300 字符的路径,预算到底花在哪了?该改哪个名字?
longpath why "D:\很深\的\路径\文件.txt"
# 删掉资源管理器删不掉的东西
longpath rm D:\卡住的\node_modulesscan(扫描):统计文件/目录数、最深嵌套、最长路径;列出超预算的路径和超出量;在 Windows 上顺带告诉你 LongPathsEnabled 策略的状态和开启命令。退出码:发现超限为 1,干净为 0。
scan --base 目标路径(复制预演):这是别的工具都没有的能力——把整棵树"虚拟拷贝"到目标文件夹再量一遍长度。OneDrive/SharePoint(同步前缀很长,总预算约 400,可配 --limit 400)、U 盘交作业、NAS 搬家、解压目标,都能提前算。
check(体检):8 条规则——too-long(超长)、reserved-name(CON/NUL/COM1 等保留名)、illegal-char(< > : " | ? * \ 及控制字符)、trailing-dot-space(结尾句点/空格)、case-collision(仅大小写不同,Windows/macOS 上互相覆盖)、unicode-collision(NFC/NFD 同名,mac 常见)、component-too-long(单个名字超 255)、undecodable-name(非法编码文件名)。--ignore 跳过规则,--exclude 跳过 vendored 目录。
why(拆解):逐组件列出累计长度,标出"预算在哪一层被击穿",并给出改名收益排行("把这个 34 字符的文件夹改短,最多省 33")。纯字符串分析——路径不需要真实存在,在 Linux 上也能直接分析日志里贴出来的 Windows 路径。
rm(强删):内部全程使用 \\?\ 扩展路径(不改注册表、不用重启);能删文件名本身就是 con、aux.txt 或结尾带句点/空格的"魔鬼文件"(git、WSL、7-Zip 都可能在 NTFS 上留下它们,资源管理器对其束手无策);自动清只读属性;绝不跟随符号链接/junction——只删链接本身,目标完好(这是把"清理临时目录"变成"清空用户资料"的经典事故,我们用真实 junction 测试过);拒绝删除盘符根目录;支持 --dry-run 预演;删除中途出错会继续删并汇总报告。
| pip 安装全平台 | 事前扫描/预演 | 仓库体检(CI) | 删除超长树 | 零依赖 | Python API | |
|---|---|---|---|---|---|---|
| longpath | ✅ | ✅ --base 预演 |
✅ 8 条规则 | ✅ | ✅ | ✅ |
| SuperDelete(C#) | ❌ 下载 exe,仅 Windows | ❌ | ❌ | ✅ | – | ❌ |
| winrmrf(2017) | ❌ 下载 exe,仅 Windows | ❌ | ❌ | ✅ | – | ❌ |
robocopy /MIR 偏方 |
系统自带 | ❌ | ❌ | ✅ 但阴间且打错就毁数据 | – | ❌ |
| Long Path Tool | ❌ | ❌ | ❌ | 💰 专门收割这个搜索词的流氓软件 | – | ❌ |
开 LongPathsEnabled |
– | ❌ | ❌ | – | – |
- MAX_PATH 是 260,但可用只有 259——计数包含结尾的
NUL终止符;目录实际约 248(要给 8.3 短文件名留位)。 - 限制按 UTF-16 码元计,不是"字符数":中文每字 1 个码元,emoji 每个 2 个码元。
longpath用len(path.encode('utf-16-le'))//2计量,而不是len(path)——大多数工具连这一点都算错。 LongPathsEnabled不是万灵药:只对 manifest 里声明了longPathAware的程序生效。所以scan会显示策略状态,但仍按 260 作为现实预算。\\?\扩展路径彻底绕过限制(上限约 32767 码元),longpath的扫描器和删除器内部全程使用它——这也是它能"看见"别的工具遍历不进去的目录的原因。
0 干净 · 1 有发现 · 2 出错。longpath <目录> 等价于 longpath scan <目录>。三个子命令都有 --json(纯 ASCII 转义,任何终端编码下都安全)。
- run: pip install git+https://github.com/hc-ui/longpath.git && longpath check .MIT © hc-ui