故障排查
诊断启动、产物、认证、权限和部署问题。
从症状出发,先检查最小的边界。
ObjectOS 无法启动
**先读日志的最后几行,再做别的。**这里有一大类启动失败是有意的拒绝,而不是 崩溃:运行时会检查它收到的配置,打印一条点名相互矛盾的变量的致命错误,然后退出。 这些消息会准确地指出问题所在,重启多少次都不会改变结果。
无论哪个版本,你最可能遇到的拒绝:
| 日志说 | 含义 |
|---|---|
| 某个数据驱动无法连接 | OS_DATABASE_URL 中的数据库 —— 或者应用把对象绑定到的某个数据源 —— 无法访问,或者其凭据错误。启动会被拒绝,而不是提供一个对每个请求都报错的服务器。 |
| 有一项待处理的破坏性模式变更,并点名了每一项变更 | 新的应用或版本需要一项会丢失数据的变更。先备份,然后用 os migrate apply --allow-destructive 有意识地应用它,再重启。 |
| 产物的期望摘要和实际摘要 | OS_ARTIFACT_URL 上的完整性固定值与获取到的字节不匹配 —— 参见下文。 |
| 端口已被占用 | os start 从不换用其他端口。释放它,或者同时修改 OS_PORT 和代理的上游。 |
| 声明了多节点拓扑 | 在一个没有多节点许可证、或协调是进程内的运行时上,OS_CLUSTER_REPLICAS 大于 1。运行一个副本 —— 参见 Docker → 多节点。 |
Cannot find module 'pg' | 裸装的 Node.js 没有 PostgreSQL 驱动。镜像中带有 pg 和 mysql2;在镜像之外,把驱动安装在 CLI 旁边(npm install -g pg)。 |
如果日志中没有致命错误,就检查常见原因:出故障的服务的容器日志,以及探针 ——
/api/v1/health 在进程提供 HTTP 服务后即有响应,/api/v1/ready 则要等数据库有
响应之后。
应用不是你预期的那个
部署所提供的应用恰好只来自一个地方,而是哪个地方是由部署声明的决策 —— 参见 启动模式。当运行中的应用不是你发布的那个时:
- **确认这个部署处于哪种模式。**如果没有设置产物引用,运行时提供的就是它的镜像
所带的内容 —— 在 Community 上,是
/srv/app/objectstack.json处的文件,或者一个 空内核加上安装进它的应用;在 Enterprise 上,是镜像中编写的元数据,加上安装进它 的任何内容。发布一个新的产物在部署指定它之前不会改变任何东西。 - 检查启动横幅,它会点名实际加载的应用。
- 不匹配的完整性固定值会拒绝启动,并同时打印期望的摘要和实际的摘要。同时打印 这两者正是关键所在:它能区分一个被重新发布的产物和一个被替换的产物。
- **没有固定值、且产物主机不可达时,启动会明确地失败。**在没有固定值的路径上没有 缓存回落 —— 没有任何东西能验证缓存副本的真实性。编排会重试;运行时永远不会自己 捏造一个不同的应用。
- 有固定值、且主机不可达时,本地缓存的副本可能会被使用 —— 但只限于其字节的 哈希仍与固定值相符的副本,并会以一条警告说明这一点。缓存在每次读取时都会重新 计算哈希;文件名从来不是依据。
- **设置一个已退役的产物变量并不会选中应用。**在企业版镜像上,其中一个会直接拒绝 启动;其他的则根本没有任何东西读取,所以部署会像你什么都没设置一样启动。 已退役的名称列出了它们 及其替代项。
没有人能登录
在全新的部署上,第一个注册的账户会成为管理员。这条规则计算的是人员,而不是
登录:一个预置了人员记录、却没有登录账户的应用会让数据库看起来已有数据,所以
注册保持关闭,而预置的人员又没有可用于登录的密码。启动日志会以 error 级别在
no_sign_in_account_at_boot 下报告这一情况。恢复要在带外进行 —— 往数据库写入一条
邀请记录,然后进行一次普通的注册;ObjectStack 的
自托管指南
逐步介绍了这一过程。要预防这种情况,就随人员一起预置登录账户,或者在第一个
管理员存在之前让目录保持为空。
登录失败
检查:
- 已配置
OS_AUTH_SECRET—— 没有它,登录端点会被完全跳过; OS_AUTH_URL和OS_TRUSTED_ORIGINS指定的是公网地址;- OIDC 回调 URL 与公网地址一致;
- ObjectOS 能访问 OIDC 发现 URL;
- 受信任的源包含公网域名;
- Cookie 的作用域是部署的公网主机名。
用户看不到记录
检查:
- 部署主机名是否正确。
- 用户是否属于预期的组织。
- 对象的
read权限。 - 行级安全。
- 共享规则或记录共享。
- 如果只是部分字段缺失,检查字段安全。
设置无法编辑
某项设置可能被环境覆盖值锁定了。生效的设置按以下顺序解析:
Environment -> Tenant -> User -> Default如果环境提供了值,运行时的编辑应当被拒绝,而不是悄悄地覆盖它。
无法读取存储的密钥
加密的设置、secret 字段和数据源凭据都用 OS_SECRET_KEY 加密。如果它们在一次
重启或恢复之后无法解密,说明密钥变了:一个从未设置它的容器自行生成了一个密钥,
并随文件系统一起丢失了,或者数据库在没有原始密钥的情况下被恢复了。设置托管备份的
原始值 —— 参见备份。新的密钥无法恢复用旧密钥加密的值。
Webhook 或作业不运行
检查:
- 产物的
requires列表包含所需的能力; - ObjectOS 镜像包含可选的服务包;
- 队列/作业服务的配置可用;
- 定时流程和 cron 作业需要
OS_AUTOMATION_SCHEDULED_WORK_ENABLED=true—— 未设置 即为关闭; - 允许访问目标的出站网络;
- 投递日志或作业运行记录在 Setup 诊断中可见。
数据库错误
检查:
- 数据库 URL 和驱动类型;
- 从 ObjectOS 到数据库的网络访问;
- 凭据和 TLS 选项;
- 模式同步/迁移日志;
- 如果使用本地 SQLite,检查存储持久化。
企业版额外提供
需许可证的镜像在启动时还会拒绝另外几种配置:
| 日志说 | 含义 |
|---|---|
| 两项设置被一起点名为不受支持的组合 | 一种无法协同工作的许可证模式和云端姿态 —— 最常见的是在一个配置为没有控制平面的部署上使用普通的、在线校验的许可证。物理隔离给出了受支持的矩阵。 |
| 隔离墙式部署需要许可证 | 在没有许可证的情况下要求了多组织租户姿态。隔离是一项需许可证的能力;运行时不会假装拥有它来提供服务。 |
| 某项决策没有做出 | 在多组织姿态下,新注册用户的成员资格策略和挂载的 AI Agent 集合都没有安全的默认值。声明任何一个可用的值都会被接受;不设置则不行。 |
| 设置了一个已退役的变量 | 旧的产物选择变量会拒绝启动,并点名它的替代项。参见已退役的名称。 |
| 缺少集群密钥 | 开启集群驱动会使一个在所有副本间共享的加密密钥成为必需。 |