故障排查
线上跑挂了去哪查、SSE 断了怎么 debug。按"症状 → 诊断步骤 → 修复"组织。
⚠️ 2026-07-05 起 GUI 已退役、NapCat QQ bot 已删除——相关条目已标注(§1 改为 hub API 排障,§7 / §9 仅存历史标题)。日常入口是
uvx openinvest <cmd>/ MCP。
← 08-deployment · Wiki 索引 · 10-design-system →
总原则
发现问题 → 先看日志,不要先猜:
# invest-web 后端
sudo journalctl -u invest-web -f --since "1 hour ago"
# Caddy(容器化)
docker logs caddy --tail 100 -f
# scheduler / cron jobs
sudo journalctl -u invest-scheduler -f
# CF Access
# 浏览器开 CF Zero Trust → Logs → Access→ 90% 的问题日志直接告诉你原因。
1. Hub API 不通(原"GUI 完全打不开",GUI 已退役)
症状
- 客户端
run.sh doctor/INVEST_API_BASE转发报连接失败、502
诊断顺序
# 1. CF 能 reach 源站吗
curl -I https://invest.your-domain.com/api/health
# → 期望 302(CF Access 重定向到登录)或带 Service Token 时 200
# 2. Caddy 在跑吗
docker ps | grep caddy
# → 期望 caddy 进程 healthy
# 3. Caddy 配置对吗
docker exec caddy cat /etc/caddy/Caddyfile | grep invest
# 4. 后端在监听吗
curl -I http://127.0.0.1:8765/api/health
# → 期望 HTTP 200
# 5. systemd 状态
sudo systemctl status invest-web常见原因 + 修复
| 症状 | 原因 | 修复 |
|---|---|---|
curl localhost:8765 Connection refused | invest-web 没起 | sudo systemctl restart invest-web |
502 Bad Gateway | Caddy 反代到的端口没人监听 | 同上 |
| Caddy 配置看着对但不生效 | bind mount + reload 不读新 inode | docker restart caddy(不是 reload) |
| CF Access 无限重定向 | Access policy 未包含你的邮箱 | CF Dashboard 加邮箱 |
2. 端点 404 但代码里有
症状
curl http://127.0.0.1:8765/api/portfolio/total_value?base=CNY
# → {"detail":"Not Found"}但代码里 src/openinvest/connectors/web_api/ 明明有这个 endpoint。
(注意:Web API 已 deprecated,不再新增端点——新功能只有 CLI / MCP 面,404 也可能 是"这个功能本来就没有 HTTP 端点"。)
原因
99% 是 systemd 进程跑的是旧代码:systemd Restart=on-failure 只在 crash 时 restart,升级包后不会自动 reload。
修复
sudo systemctl restart invest-web
sleep 2
curl http://127.0.0.1:8765/api/portfolio/total_value?base=CNY
# → {"base_currency":"CNY","grand_total":...}→ 每次升级后端包必须手动 restart。详见 08-deployment.md#升级流程。
长期方案
deploy 脚本里固化"升级 + restart"两步。
3. 委员会触发后没反应 / SSE 不直播
症状
远端触发委员会(客户端 run_committee 经 hub / 内部触发)后 task_id 出来了,但状态一直 queued 或 running 不动。
诊断
# 1. 任务状态文件存在吗
ls ~/openInvest/memory/.committee/<task_id>/
# 2. status.json 在变吗(每个 stage 完成会写)
watch -n 1 cat ~/openInvest/memory/.committee/<task_id>/status.json
# 3. journal 里 LLM 调用在跑吗
sudo journalctl -u invest-web --since "5 minutes ago" | grep -i "deepseek\|httpx"
# 4. SSE 端点能直接 curl 吗
curl -N http://127.0.0.1:8765/api/committee/live/<task_id>
# 期望持续输出 event: progress / data: ...常见原因
| 症状 | 原因 | 修复 |
|---|---|---|
| status.json 一直 queued | asyncio.create_task 没起 | 检查 journal 是否有 traceback;restart 后端 |
| LLM 一直没 200 | DeepSeek API key 错 / 限速 / 余额不足 | .env 检查 / journal 看 401 / 429 |
A 股 / 港股委员会报「无 XXX 行情数据」,日志有 yfinance sync failed ... 429 | Yahoo 限流(大陆服务器常见),库里又没有历史价 | 配 EQUIBLES_API_KEY 走行情兜底,见 22-configuration.md(ETF 不覆盖) |
| status.json 跳到 done 但 SSE 消费方没收到 | SSE 连接被 CF Access 5min idle 切了 | 检查代码 keepalive 是否在跑(25s 一次) |
| running 但 LLM 一直没调 | 被锁住(其他 task 占了 fcntl 锁) | lsof memory/portfolio.md.lock 找出占用方 |
v3 收敛检测看着像 bug
看到 final_round: 3, converged: true, max_debate_rounds: 4 不要慌—— 这是收敛提前退出,不是 round 4 没跑完。详见 02-agents.md#收敛检测。
4. yfinance 拉不到价 / 行情陈旧
症状
uvx openinvest status / live_prices 报"⚠ 陈旧",或行情字段是 null。
诊断
# 直接试拉一个 symbol
uvx openinvest live_prices
# 开发仓形态:
uv run python -c "from openinvest.utils.exchange_fee import get_history_data; df = get_history_data('NDQ.AX', '5d'); print(df.tail())"常见原因
| 症状 | 原因 | 修复 |
|---|---|---|
403 Forbidden 反复出现 | yfinance 被 IP 限速 | 等 5-10min;或换 yfinance proxy 设置 |
| df 是 None | symbol 错 / yfinance 不覆盖 | 在 https://finance.yahoo.com 验证 ticker 是否存在 |
| Close 列为空 | 周末 / 假期没新数据 | 这是正常的,DB 兜底应该接管 |
| BetaShares 403 NDQ.AX 拉不到 | NDQ 走自家 scraper 失败 | yfinance fallback 自动接(journal 里看到 🔄 yfinance fallback) |
数据源全景诊断
uvx openinvest doctor 一眼看所有数据源最后成功时间 + is_stale (hub 上也可 GET /api/data_sources/health)。
5. CommSec 邮件没拉到成交
症状
下单后过几小时,portfolio.md 里没有新 holding。
诊断
# v3 改了:CommSec 默认 disable cron,必须手动触发
uv run python -m scripts.import_commsec --lookback 30
# 期望显示拉到的成交列表(dry-run)
# 真正写入
uv run python -m scripts.import_commsec --lookback 30 --apply常见原因
| 症状 | 原因 | 修复 |
|---|---|---|
IMAP 连接失败 | EMAIL_PASSWORD 不是应用密码 | Gmail 必须用 应用密码,不是登录密码 |
| 拉到 0 条 | lookback 太短或邮件已被 processed | --lookback 365 重试 |
| 拉到了但写入失败 | symbol 不在 strategy.target_assets | 先去 strategy 加;或先 add holding |
为什么默认 disable cron
cron 自动同步在 IMAP 临时失败时会静默漏成交,导致 portfolio 和真实账户对不上。 改手动模式让用户先 dry-run 看清楚再 apply。详见 05-data-model.md。
6. PnL 图表数据不对 / 跳楼
症状
/api/pnl_chart.svg 折线断崖、有未来日期。
诊断
# pnl_history.jsonl 直接看
tail -20 ~/openInvest/memory/pnl_history.jsonl
# 找时间戳异常的行(凌晨非交易时段、未来时间)常见原因
| 症状 | 原因 | 修复 |
|---|---|---|
| 凌晨有数据点 | pnl_snapshot job 在工作时段外被触发 | python -m scripts.clean_pnl_history --dry-run 然后真删 |
| 未来日期 | 时区配置错(UTC vs Asia/Shanghai) | .env TZ=Asia/Shanghai 同步 |
| 某天垂直跳变 | 用户没记账,scheduler 仍在跑 | 用 `/api/cash/CNY/deposit |
| 图一直是「数据采集中」 | job 返回 skipped:insufficient_history(账本不足 2 个估值日,看 status 的 performance)或 unvalued_holdings(有持仓拉不到价 / 汇率,这次不记点,免得曲线假跌) | 补记账本 / 修行情源后下一轮自动接上 |
清理脚本:
python -m scripts.clean_pnl_history --dry-run # 预览
python -m scripts.clean_pnl_history # 实际执行(自动备份)
python -m openinvest.jobs.pnl_snapshot --render-only # 重渲染 SVG7. sync_gui_dist 失败(已退役 2026-07-05)
scripts.sync_gui_dist 已随 GUI 壳层删除,后端不再拉/serve 前端 dist。 invest-gui 仓库封存待重做(重做走独立前端连 MCP)。
8. 测试挂了
症状
uv run pytest tests/
# FAILED tests/test_xxx.py诊断
# 单独跑挂的那个 + verbose
uv run pytest tests/test_xxx.py::test_yyy -v --tb=long常见原因
| 症状 | 原因 | 修复 |
|---|---|---|
yfinance 拉数据失败 | 网络 / 限速 | 重跑几次;或加 mock |
ImportError 不能 import _render_portfolio_body | v2 改名 → _render_portfolio_body_v2 | CI 修过;本地代码可能旧 |
ValidationError schema_version | portfolio.md 不符 v2 schema | 跑 python -m scripts.migrate_portfolio_to_holdings |
账本已含非有限数(cash.CNY) / finite_number | portfolio.md 里已存着 .nan / .inf(旧版 deposit -a nan 写坏),修好前所有写操作都会被拒 | 手动编辑 memory/portfolio.md,把该字段改回正确数值即可(读取不校验,无需迁移) |
166 测试是底线,加新功能必须保持全绿。
9. NapCat QQ bot 不响应命令(connector 已删除 2026-07-05)
NapCat QQ bot connector 已从代码库删除,NAPCAT_* / INVEST_WHITELIST_QQ env 不再生效。要在聊天软件里用 openInvest,走 MCP(openinvest-mcp)接任意支持 MCP 的 agent 宿主。
10. 应急联系 / 找历史
- 历史决议:
memory/daily/<date>/<symbol>.md - LLM 调用 telemetry:
memory/llm_usage.jsonl - Tool 调用审计:
memory/.committee/<task_id>/tool_calls.jsonl - Dreaming 事件:
memory/.dreams/events.jsonl - 委员会任务状态:
memory/.committee/<task_id>/status.json
→ 几乎所有"为什么 AI 这次说 BUY"的问题都能从这些文件复盘。
下一步
→ 08-deployment.md — 部署相关问题
→ QUICK_START.md Troubleshooting 章节 — fork 用户安装期的问题
→ 还有问题没解决?开 GitHub Issue