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 里的目录就是嫌疑。
2. Symlink 环
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。Zscaler(Cursor 网络配置文档直接点名它是「最常见的有这类限制的代理」)、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% 才亮。
Step 4:拆 symlink 环
对前面找到的每个回指上级的 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 卡住