CodeGraph 故障排查完全指南:从"未初始化"到 `database is locked` 的六类常见问题与源码级解决方案
CodeGraph 是一个预构建代码知识图谱工具,通过本地 SQLite 索引为 Claude Code、Codex、Gemini、Cursor 等 Agent 提供低开销的代码检索与探索能力,并随代码变更自动同步。本文基于官方故障排查文档,完整覆盖六个最高频问题的排查与修复路径——初始化缺失、索引缓慢、SQLite 锁竞争、MCP 连接失败、符号缺失、Windows/WSL 双环境共享检出——并结合 src/ 下的真实实现(连接 PRAGMA 配置、WAL 模式判定、CODEGRAPH_DIR 环境变量解析、文件监听降级逻辑)给出每一处结论的源码依据,帮助你定位问题时能直接读到对应的判定逻辑。
问题一:"CodeGraph not initialized"(未初始化)
症状:运行 codegraph 相关命令或 Agent 调用 MCP 工具时,提示 CodeGraph not initialized in <项目路径>。
解决方法:先在项目目录下执行 codegraph init。
这条错误信息并非简单文案,它来自明确的初始化判定逻辑。"已初始化"在 CodeGraph 中有严格定义,需要同时满足两个条件:
- 项目根目录下存在
.codegraph/目录; - 该目录下存在
codegraph.db数据库文件(仅有空目录不算初始化)。
这个判定实现在 isInitialized:
export function isInitialized(projectRoot: string): boolean {
const codegraphDir = getCodeGraphDir(projectRoot);
if (!fs.existsSync(codegraphDir) || !fs.statSync(codegraphDir).isDirectory()) {
return false;
}
// Must have codegraph.db, not just .codegraph folder
const dbPath = path.join(codegraphDir, 'codegraph.db');
return fs.existsSync(dbPath);
}
从源码结构看,当判定失败时,核心引擎会在 src/index.ts 中抛出 CodeGraph not initialized in <root>. Run init() first.;而 CLI 各子命令(index、sync、node、context 等)在 src/bin/codegraph.ts 中都会先做同样的检查并输出统一报错。此外还有两种衍生情况值得注意:
- 误删了数据库文件:如果你曾手动删除
codegraph.db但保留了.codegraph/目录,init会拒绝重复创建。此时删除整个.codegraph目录后重新codegraph init即可(错误提示中也会给出该建议,见 src/index.ts)。 - 在子目录中运行:CodeGraph 会沿目录树向上查找最近的已初始化项目根(类似 git 找
.git),实现为 findNearestCodeGraphRoot。如果整个目录树都未初始化,报错才会出现——请确认你在项目目录内运行命令,或传入显式路径参数。
另外,MCP 工具层对未初始化项目有专门的"降级引导":当 Agent 调用工具时报 CodeGraph isn't available here — no .codegraph/ index exists,并附带提示 Agent 应改用自己的内置工具、由项目所有者决定是否执行 codegraph init(见 src/bin/codegraph.ts)。这是有意设计,避免 Agent 越权自动建索引。
问题二:索引速度慢
排查与优化手段(官方文档给出的两条核心建议):
- 确认大目录已被排除。
node_modules等大目录只要被 gitignore 了就会被排除在索引之外。如果你的项目里出现未被 gitignore 的产物目录(生成代码、构建输出等),建议将其加入.gitignore或 CodeGraph 的排除配置。从源码结构看,子项目扫描本身就内置了一份"永不进入"的目录黑名单(node_modules、dist、build、target、vendor、.venv等),定义在 SUBPROJECT_SCAN_SKIP。 - 使用
--quiet降低输出开销。codegraph index支持-q, --quiet选项以抑制进度输出(见 src/bin/codegraph.ts),在慢速终端或远程机器上可减少终端渲染带来的额外开销。
源码层面的补充说明:CodeGraph 的索引流水线本身已针对慢磁盘做过深度优化。以 WAL(写前日志)管理为例,src/db/wal-valve.ts 的文件头注释记录了实测数据:SQLite 默认的 wal_autocheckpoint 在批量索引时会把热 B-tree/FTS 页反复写回主库文件,占全部磁盘 I/O 的约 95%,在 HDD 级存储(约 150 随机 IOPS)上使索引耗时从 45 秒劣化到 19 分钟以上。为此 CodeGraph 在批量索引期间延迟自动 checkpoint,并引入"WAL 阀"机制:
- 软阈值(默认 256 MB,可用
CODEGRAPH_WAL_VALVE_MB覆盖,大项目按数据库体积自动放大到dbSize/4且上限 2 GB)触发工作线程上的PRAGMA wal_checkpoint(PASSIVE)回补; - 超过 2 倍软阈值的硬上限时,写入端会在事务间边界暂停,等待一次完整回补;
- 可用
CODEGRAPH_WAL_VALVE_DEBUG=1将阀门决策输出到 stderr 辅助诊断(见 WalCheckpointValve 构造函数)。
因此如果你观察到索引慢且磁盘 I/O 打满,可以先确认日志中是否有 [wal-valve] 的暂停记录,判断是磁盘追不上写入速度还是配置问题。
问题三:MCP 命中 database is locked
官方文档的结论是:当前版本不应该再出现这个问题。原因有二,均有源码直接佐证:
- 内置 Node 运行时 +
node:sqlite:CodeGraph 发布版自带 Node 运行时,直接调用 Node 内置的真实 SQLite(node:sqlite,无 wasm 回退、无原生编译步骤),WAL 与 FTS5 全量可用。这一设计说明在 src/db/sqlite-adapter.ts 的模块注释中:"node:sqlite (real SQLite, with WAL + FTS5) is always available — there is no native build step and no wasm fallback." - WAL 模式下并发读永不阻塞写者:每个连接建立时统一应用一组 PRAGMA(
initialize与open两条路径共享同一函数,防止行为漂移),见 configureConnection:
function configureConnection(db: SqliteDatabase): void {
db.pragma('busy_timeout = 5000'); // MUST be first — 先设超时的注释说明
db.pragma('foreign_keys = ON');
db.pragma('journal_mode = WAL'); // node:sqlite supports WAL on every platform
db.pragma('synchronous = NORMAL'); // safe with WAL mode
db.pragma('cache_size = -64000'); // 64 MB page cache
db.pragma('temp_store = MEMORY');
db.pragma('mmap_size = 268435456'); // 256 MB memory-mapped I/O
db.pragma(`journal_size_limit = ${WAL_HEAL_THRESHOLD_BYTES}`);
}
注意 busy_timeout = 5000 被刻意放在最前面——注释解释了原因:如果打开数据库文件时另一个进程正持有写锁,先设置超时就让后续 PRAGMA 和首条查询"等锁"而不是立刻抛出 database is locked(对应 issue #238)。且 WAL 下读永远不阻塞写,该超时只管辖跨进程写竞争(例如 git hook 触发的 codegraph sync 与 MCP 服务写库同时进行)。
如果你仍然看到 database is locked,按文档排查两个方向:
-
你用的是 0.9 之前的旧安装:旧版没有内置运行时,锁行为不可靠。重新安装即可获得内置运行时:
- macOS/Linux:
curl -fsSL https://raw.githubusercontent.com/colbymchenry/codegraph/main/install.sh | sh - Windows:
irm https://raw.githubusercontent.com/colbymchenry/codegraph/main/install.ps1 | iex - 或
npm i -g @colbymchenry/codegraph@latest
- macOS/Linux:
-
codegraph status显示Journal:不是wal:说明该文件系统上 WAL 无法生效(网络共享盘、WSL2 的/mnt挂载点常见),此时读会阻塞在写后面。解决办法:把项目(连同其.codegraph/目录)移动到本地磁盘。
Journal: 这一行正是 codegraph status 中用来验证 WAL 是否生效的诊断字段,其渲染逻辑在 src/bin/codegraph.ts:
const journalLabel = journalMode === 'wal'
? chalk.green('wal')
: chalk.yellow(`${journalMode || 'unknown'} ${getGlyphs().dash} WAL inactive; reads can block on writes`);
console.log(` Journal: ${journalLabel}`);
源码注释进一步点明:node:sqlite 在所有平台都支持 WAL,所以非 wal 模式几乎总是"文件系统不支持"的信号(见 issue #238 的相关注释,位于同一文件的 L1072-L1075)。MCP 工具层同样会在响应中暴露该信息:当模式非 wal 时,工具输出会带 **Journal mode:** ⚠ … WAL not active, so reads can block on writes 的警告(见 src/mcp/tools.ts)。
问题四:MCP 服务器连不上
关键认知:MCP 服务器由你的 Agent(Claude Code、Cursor 等)自行拉起,不需要也不应该手动启动。排查顺序如下:
- 确认项目已初始化且已索引:运行
codegraph status,应能看到Project:、Index Statistics:(Files/Nodes/Edges/DB Size)等输出,而不是Not initialized。 - 核对 MCP 配置中的项目路径:配置里指向的路径必须是已初始化的项目根(或会被向上查找解析到的目录)。
- 重写配置:若路径正确仍连不上,重新运行
codegraph install,它会按你使用的 Agent 重写对应 MCP 配置。install命令支持--init选项在同一步完成建索引(见 src/bin/codegraph.ts)。
从源码结构看,服务器侧有一套完整的守护与生命周期管理(src/mcp/ 下的 daemon-manager.ts、daemon-registry.ts、daemon-paths.ts、liveness-watchdog.ts 等),文件监听与自动同步的启动会向日志输出 [CodeGraph MCP] File watcher active — graph will auto-sync on changes(见 src/mcp/engine.ts)。若你在 MCP 日志中看到监听已激活却仍"无响应",多半是配置路径解析到了错误的目录树;install 的各 Agent 适配器(src/installer/targets/)会针对每个客户端生成对应的配置写入方式,重跑一次是修复配置漂移最可靠的手段。
问题五:缺少符号(Missing symbols)
排查三步法:
- 等待自动同步。MCP 服务器内置文件监听,保存文件后会触发自动同步(见 src/mcp/engine.ts:
graph will auto-update; run codegraph sync的降级提示),等两三秒让增量同步完成。 - 手动同步。若等待后仍缺失,手动执行
codegraph sync强制增量同步。 - 确认文件可被索引:
- 文件语言是否在 受支持语言列表 中;
- 文件是否位于被
.gitignore忽略或默认排除的目录中(例如node_modules、dist)——这类目录本来就不进索引,其中的符号自然"缺失"。
与自动同步相关的补充细节(帮助判断"到底是没同步,还是同步被禁用了"):
- 服务器会周期性做陈旧度检查。如果工具响应开头出现
⚠️ Some files referenced below were edited since the last index sync…横幅,说明只是少量文件待重索引——横幅中列出的文件需直接 Read 获取最新内容,其余文件仍可信任图谱(该横幅语义定义在 src/mcp/server-instructions.ts)。 - 另一种更罕见的横幅
⚠️ CodeGraph auto-sync is DISABLED — live file watching stopped表示整个索引已冻结(通常是 OS 文件监听限制耗尽),此时应对所有可能变更的内容直接读文件确认,并手动codegraph sync(见 src/mcp/tools.ts 与 src/sync/watcher.ts:OS watch/file limit exhausted; auto-sync disabled)。 - 监听降级是有预算的:src/sync/watcher.ts 的注释说明,短暂的写锁竞争(重试预算内)会等待,只有确定性失败(如 tree-sitter 解析错误)或竞争耗尽重试预算时才会禁用自动同步并降级。
问题六:Windows 与 WSL 共享同一个检出(checkout)
核心结论:不要让两侧指向同一个 .codegraph/。 原因有二(官方文档与源码注释完全一致):
- 后台服务器锁与 SQLite 索引都"绑定"于写入它们的操作系统。
.codegraph/daemon.pid记录的是平台相关的 pid 与 socket 路径——Windows 上是命名管道,WSL 上是 Unix socket,两者互不兼容; - SQLite 文件锁跨 WSL2 ↔ Windows 文件系统边界不可靠。两个 daemon 共享一个索引会导致损坏。
正确做法:给其中一侧设置 CODEGRAPH_DIR 指向独立目录名,让同一棵项目树里各自持有独立索引。例如 Windows 侧设置 CODEGRAPH_DIR=.codegraph-win,WSL 侧保持默认 .codegraph。
该机制的实现细节值得展开,全部在 src/directory.ts:
export function codeGraphDirName(): string {
const raw = process.env.CODEGRAPH_DIR?.trim();
if (!raw) return DEFAULT_CODEGRAPH_DIR; // 默认 '.codegraph'
const invalid =
raw === '.' || raw.includes('..') ||
raw.includes('/') || raw.includes('\\') ||
path.isAbsolute(raw);
if (invalid) { /* 警告一次并回退默认值 */ return DEFAULT_CODEGRAPH_DIR; }
return raw;
}
要点:
- 校验规则:
CODEGRAPH_DIR必须是单个纯目录名——不能为空、不能含路径分隔符、不能是./..或绝对路径。非法值会被忽略并回退到默认.codegraph,同时向 stderr 警告一次(不能走 stdout,因为那是 MCP 协议通道)。这保证索引绝不会写到项目目录之外。 - 索引目录互不干扰:isCodeGraphDataDir 会把默认
.codegraph、当前生效的CODEGRAPH_DIR覆盖值以及任何.codegraph-*兄弟目录都识别为"CodeGraph 数据目录";文件监听与索引过程会跳过所有这些目录。因此 Windows 的.codegraph-win永远不会出现在 WSL 侧的监听/索引目标里,反之亦然——这正是文档所说"the two never trip over each other"的源码保证。 - 慢速文件系统提示:如果你的 WSL 项目位于
/mnt下(对 WSL 而言是 Windows 文件系统,慢且锁行为不可靠),codegraph index提供--no-watch选项关闭文件监听(帮助文本明确写道"useful on slow filesystems like WSL2 /mnt drives",见 src/bin/codegraph.ts);但更彻底的方案仍是把项目放到 WSL 本地文件系统,同时解决慢与锁两类问题。
附:快速自检清单
把六个问题串成一条排查流水线,遇到异常时可以按序执行:
| 步骤 | 命令/动作 | 期望结果 |
|---|---|---|
| 1 | codegraph status |
显示 Project:、Index Statistics:;Not initialized 则先 codegraph init |
| 2 | 查看 Journal: 行 |
显示绿色的 wal;否则见问题三(旧安装 / 非本地文件系统) |
| 3 | 查看 DB Size / WAL Size 行 |
WAL 正常时应小于 DB;若 WAL Size 大于数据库并被黄色标出,说明有被杀会话遗留(打开时会自动回收,见 WAL_HEAL_THRESHOLD_BYTES 的自动修复机制,可用 CODEGRAPH_WAL_HEAL_MB 调整阈值,默认 64 MB) |
| 4 | 检查 codegraph status 中的警告行 |
indexing/partial/failed 状态提示重跑 codegraph index;pendingRefs 非零提示运行 codegraph sync 补全中断的解析(对应 src/bin/codegraph.ts) |
| 5 | 确认 MCP 配置路径 | 路径错误则重跑 codegraph install 重写配置 |
| 6 | Windows/WSL 双环境 | 为一侧设置 CODEGRAPH_DIR=.codegraph-win,两侧各持独立索引 |
以上所有判定逻辑(初始化条件、journal 模式展示、状态机警告、目录名解析)都直接对应 src/directory.ts、src/bin/codegraph.ts、src/db/index.ts 中的实现,排查遇到本文未覆盖的新症状时,可以按错误信息中的关键词在这些文件中检索对应分支,快速定位触发条件。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00