Cursor 索引一直跑不完:7 类原因和修法

Cursor 索引进度条转了几个小时不动,多半是仓库太大、没写 .cursorignore、公司 HTTP/2 代理被拦、symlink 环或权限不足。本文教你先判断属于哪一类再对症修。

Cursor Settings → Indexing 顶上写着 “Indexing… 3,432 of 1,200,000 files”,半小时后再看还是这个数;有时干脆 spinner 一直转停在 0%。这件事影响很大:Cursor 的语义搜索要到索引完成 80% 才会真正打开(见 Cursor 索引官方文档),在那之前 @Codebase 的回答和 Agent 找文件其实都是「盲」的。

最常见的原因不是 Cursor 的 bug,而是 .cursorignore 没覆盖 node_modules 和 build 产物,结果把上百万个生成文件全丢进了向量化流程。2026 年新冒出来的第二大原因是:公司的 SSL 解密代理(Zscaler、Netskope)悄悄掐断了 Cursor 上传 embedding 用的 HTTP/2 连接。下面先教你判断自己属于哪一类,再针对性地排除或改配置。

一句话速查

  • 索引停在一个很大的文件数上 → 你的 .cursorignore 漏了 build/cache 目录,看 Step 1。
  • 进度卡 0%、报 “Handshake Failed”、连 chat 和 Tab 也挂了 → 公司代理拦了 HTTP/2,打开 Disable HTTP/2 开关并彻底重启 Cursor(Step 2)。
  • 只在一个仓库出问题 → ignore 配置、symlink 或规模问题。所有仓库都出问题 → 多半是网络/代理,或 Cursor 装坏了。
  • 语义搜索要索引到 80% 才能用(见 Cursor 索引官方文档);之后索引每 5 分钟自动同步一次,只处理改动过的文件;仓库连续 6 周没动静,Cursor 会把缓存的索引丢掉。

先判断属于哪一类

在仓库根先跑这几条,它们能告诉你该跳到哪一步。

git ls-files | wc -l                 # 如果 .cursorignore = .gitignore,Cursor 会索引的文件数
find . -type f 2>/dev/null | wc -l   # 磁盘上全部文件,含 ignored
du -sh node_modules .next dist build coverage target 2>/dev/null | sort -h
find . -type l 2>/dev/null | head -20            # symlink(环的嫌疑)
df -h .                                          # 挂载类型(网络盘/同步盘?)

如果第 2 行远大于第 1 行,就是有没排除的生成文件(原因 1)。如果某个 symlink 指向上级目录,怀疑是环(原因 2)。如果 df 显示 SMB/NFS 或路径是 iCloud/Dropbox,怀疑 IO 延迟(原因 5)。如果索引卡 0% 且 chat/Tab 一起挂,直接跳到代理那一节(原因 6)。

常见原因

1. node_modules / dist / .next / build 没被排除

Cursor 默认尊重 .gitignore 和自带的默认忽略列表,但很多团队的 .gitignore 里有 node_modules,却漏了 dist/coverage/.next/.turbo/__pycache__/venv/。一个 Next.js monorepo 里 .next/cache/webpack 一项就能有 50 万文件,向量化流程会老老实实把每一个都切块。

如何判断:上面 du -sh 里最大、又不在 .gitignore 里的目录就是嫌疑。

packages/web/node_modules/internal-pkg -> ../../shared,而 shared 又 symlink 回去,扫描会无限递归。

如何判断

find . -type l -exec ls -l {} \; 2>/dev/null | grep -E "\.\./.*\.\./"

任何回指上级目录的 symlink 都是候选。

3. 仓库整体超出实用索引规模

官方没有公布硬性文件上限,但 Cursor 自己的说法是「几万个文件的大仓库可能要索引好几个小时」,而且「对大多数团队,正确做法是写一份紧凑的 .cursorignore,而不是关掉索引」。就单个文件而言,超过约 5,000 行的(压缩 bundle、生成的 protobuf/GraphQL/OpenAPI 客户端)会拖累分词器,纯属浪费索引空间。

如何判断:排除之后 find . -type f | wc -l 还超 10 万,就已经过了舒适区——与其干等,不如缩小工作目录(Step 5)。

4. 权限不足

某个目录归 root 所有(系统路径、Docker volume),Cursor 进程读不进去,索引器就卡在那等。

如何判断

find . -not -readable 2>/dev/null | head

5. 网络盘 / WSL 跨边界

项目放在 SMB / NFS / Dropbox / iCloud 同步盘上,单文件读写延迟飙到 100ms 以上,索引器吞吐降两个数量级。本地 SSD 上 4 分钟能索引完的 3 万文件仓库,放同步目录里可能要好几个小时。

如何判断df -h . 看挂载类型;路径是 /mnt/c/...(WSL)或 ~/Library/Mobile Documents/...(iCloud)就是信号。

6. 公司代理拦了 HTTP/2(2026 年的新坑)

Cursor 用 HTTP/2 双向流来传 embedding、chat 和 Tab。ZscalerCursor 网络配置文档直接点名它是「最常见的有这类限制的代理」)、Netskope 这类 SSL 解密代理常常会缓冲或掐断 HTTP/2 流,于是索引请求被截断、变成乱码或超时——界面就只是停在 0% 或者抛 “Handshake Failed”。理论上 Cursor 会自动回退到 HTTP/1.1 的 server-sent events,但自动检测经常识别不出解密代理,所以 Step 2 要你手动去拨那个开关。判断信号是:索引、chat、Tab 自动补全同时全挂,所有仓库都这样,而且只在公司网络下发生。

如何判断:用手机热点正常,连办公室 Wi-Fi/VPN 就卡?那就是代理。

7. Cursor 自身索引服务卡死

extension host 崩了,或者 index worker 进程死了,但 UI 不更新。

如何判断Cmd+Shift+P → “Developer: Show Running Extensions”,Cursor 的 index worker 显示 unresponsive。

动手前先确认

  • 确认是这一个仓库的问题,还是所有仓库都索引不动。所有仓库都不动通常指向代理(原因 6)或 Cursor 装坏了。
  • 改之前先 commit 一次 .cursorignore,方便回滚。
  • 记下 Cursor 版本、仓库文件总数、操作系统、订阅档(Hobby / Pro / Pro+ / Business)。
  • 看一眼 status.cursor.com——Cursor 服务端出过索引故障,那种情况本地怎么修都没用。

最短修复路径

按收益从高到低排。

Step 1:写一份合格的 .cursorignore

仓库根新建或编辑 .cursorignore,语法和 gitignore 一样(***?! 用来反向重新包含、# 是注释):

# 依赖
node_modules
.pnpm
.yarn
vendor
__pycache__
venv
.venv

# 构建产物
dist
build
out
.next
.nuxt
.turbo
.svelte-kit
coverage
target
.gradle

# 缓存
.cache
.parcel-cache
.eslintcache
*.tsbuildinfo

# 数据 / 二进制(浪费 embedding 预算)
*.parquet
*.bin
*.gz
*.zip
*.sqlite
*.min.js
*.min.css

# 日志
*.log
logs

要分清两个 ignore 文件的区别(出自 Cursor ignore-file 参考文档):

文件排除出索引仍能手动 @ 引用 / 被 Agent 用适合放什么
.cursorignore——语义搜索、Tab、Agent、Inline Edit、@ 引用全都拦死.env、密钥、node_modules、build 垃圾
.cursorindexingignore——只是不进搜索索引,你还能手动挂上去偶尔要看的大型生成文件 / vendored 代码

约 90% 的情况只用 .cursorignore 就够了。注意:Agent 跑的终端命令和 MCP server 工具是不受 .cursorignore 约束的,所以它并不是一道硬性的密钥边界。

Step 2:如果 chat 和 Tab 也挂了——先修 HTTP/2

如果索引卡 0% 而且整个 app 在公司网络下没反应,就手动强制走 HTTP/1.1 回退。打开设置(Cmd/Ctrl + ,),搜 http2,打开 Disable HTTP/2 开关。在 settings.json 里(Cmd+Shift+P → “Preferences: Open User Settings (JSON)“)的等价写法是:

"cursor.general.disableHttp2": true

然后彻底退出再重开 Cursor——“Developer: Reload Window” 不会重载网络栈,不重启的话改动不生效。这之后 Cursor 走 HTTP/1.1 的 server-sent events:流式稍慢一点,但能穿过 SSL 解密代理。据反馈,这一招能解决大约 70% 的公司网络索引故障。如果是公司自建代理,更干净的长期做法是让 IT 把 *.cursor.com 从 SSL 检测里加白名单,而不是把所有开发者都降到 HTTP/1.1。

Step 3:触发一次干净的 reindex

打开 Cursor Settings → Indexing(新版叫 Indexing & Docs),用 Resync Index;如果不生效,再用 Delete and Reindex。然后 Cmd+Shift+P → “Developer: Reload Window”。重建索引不会动到任何源码——你丢掉的只是缓存的 embedding,下次打开会重建(普通仓库几分钟)。盯着进度,记住搜索要到 80% 才亮。

对前面找到的每个回指上级的 symlink,要么把它加进 .cursorignore,要么改成 npm / pnpm / yarn workspaces 这类原生链接,而不是裸文件系统 symlink。

Step 5:缩小工作目录

别在 5 万文件的 monorepo 根打开 Cursor。File → Open Folder → 选你这周实际在做的那个包(apps/web)。索引面立刻小一个量级,而且噪声少了,搜索质量也更好。

Step 6:从网络盘 / 同步盘搬到本地

git clone 到一个原生本地路径(macOS APFS 上的 ~/repo、WSL ext4、Linux 本地盘)。active 项目绝不要放在 Dropbox / iCloud / 网络挂载里。

Step 7:核选项——清空 workspace storage

# macOS / Linux
rm -rf ~/Library/Application\ Support/Cursor/User/workspaceStorage/*
# Windows(PowerShell)
# Remove-Item -Recurse -Force $env:APPDATA\Cursor\User\workspaceStorage\*

这会清掉所有 workspace 的索引缓存,下次打开每个仓库都要重新索引。万不得已才用。

怎么确认已经修好

  • 重启 Cursor 后再触发一次,确认不是会话内的临时状态。
  • 索引在合理时间内走到 100%(普通仓库在本地 SSD 上是几分钟,不该是几小时)。
  • 打开 Cursor Settings → Indexing & Docs → View included files,看实际索引进去的是哪些——文件数应当约等于 git ls-files | wc -l 减去 .cursorignore 命中的,而且 node_modules / build 目录应当不在里面。
  • 让 Composer「列出 src/api/ 下所有文件」——能给出完整正确的列表,才证明索引真的覆盖到了整棵树。

如果还是没修好

  • 把复现缩到最小:新开一个空仓库看是否也卡。如果也卡,问题在 Cursor/网络,不在你的仓库。
  • 回滚最近一次 Cursor 升级或 .cursorignore 改动。
  • 在 forum.cursor.com 搜 “indexing never completes” 或 “Handshake Failed”;附文件数、OS、ignore 全文。
  • 抓 Help → Toggle Developer Tools → Console 里 indexing 相关日志,贴到 Bug Reports。

预防建议

  • 新仓库第一件事就放好 .cursorignore,别等卡住再补。
  • .cursorignore.gitignore 维护差异:模型确实需要看的 generated types / schema 留在索引里;node_modules 和 build 产物永远排除。
  • 不要把数据集(parquet / sqlite / 大 json)放进仓库,用 git-lfs 或 S3,并且照样 ignore。
  • 项目永远放原生文件系统,别放 iCloud / Dropbox / 网络盘。
  • 公司电脑上,在撞墙之前就先打开 Disable HTTP/2(或让 IT 把 *.cursor.com 从 SSL 检测里加白名单)。
  • 每个季度跑一次 git ls-files | wc -l。超过约 5 万文件,考虑拆 monorepo 或把 Cursor 限定到单个包。

常见问题

为什么 Cursor 显示索引完成了,@Codebase 还是答错? 搜索要到完成 80% 才激活,所以「完成」标记可能比全量覆盖来得早。另外确认那个文件没被 .cursorignore 排掉——那会把它彻底挡在搜索之外,而不只是不索引。

删索引会丢代码吗? 不会。索引只是和你文件分开存的缓存 embedding。Delete and Reindex 会在下次打开时重建,绝不改源码。(仓库连续 6 周没动静,Cursor 自己也会把缓存索引丢掉,下次打开项目时重建——这一次性的重建是正常的,不是 bug。)

.cursorignore.cursorindexingignore 有什么区别? .cursorignore 把一个文件从所有 AI 功能里彻底挡住(搜索、Tab、Agent、Inline Edit、@)。.cursorindexingignore 只是不让它进搜索索引——你还能手动把它当上下文挂上去。密钥和垃圾用前者,偶尔要引用的大型生成文件用后者。

在家正常,到公司网络就卡,为什么? 几乎都是 SSL 解密代理(Zscaler / Netskope)缓冲或破坏了 HTTP/2。在设置里搜 http2 打开 Disable HTTP/2 开关,或者写 "cursor.general.disableHttp2": true,然后彻底退出再重开 Cursor——光 reload window 不会重载网络栈。

首次索引之后,Cursor 多久重新索引一次? 自动每 5 分钟一次,而且只处理改动过的文件——所以一次性的大型首轮索引是正常的,稳态下的同步开销很小。

相关阅读

标签: #排查 #Cursor #排查 #indexing 卡住