错误
任何 2xx 之外的响应都带一个 JSON 体。请根据 code 分支,绝不要根据 message——消息是写给人看的,随时可能改措辞。
外层结构
{
"detail": {
"code": "INSUFFICIENT_BALANCE",
"message": "Add credits before deploying an instance",
"balance_microusd": 0,
"required_microusd": 2290000
}
}
| 键 | 类型 | 含义 |
|---|---|---|
detail.code | 字符串 | 稳定、全大写,可以放心用来分支 |
detail.message | 字符串 | 一行给人看的解释 |
| 额外的键 | 视情况而定 | 针对这次具体失败的上下文 |
有两类失败用的是另一种结构。框架抛出的请求校验错误会在 detail 下放一个列表,每个有问题的字段一条:
{"detail": [{"type": "greater_than_equal", "loc": ["body", "disk_gb"], "msg": "Input should be greater than or equal to 10"}]}
而意料之外的服务端故障会在那里放一个纯字符串,比如 {"detail": "Internal Server Error"}。如果你在写客户端库,这三种形态都要处理。
HTTP 状态码
| 状态码 | 含义 |
|---|---|
| 200 | 请求成功 |
| 201 | 创建出了某个东西——一个实例、一份模板副本、一个 API 密钥 |
| 204 | 成功但没有响应体:吊销密钥、删除 SSH 密钥 |
| 400 | 请求本身有毛病,比如 X-Org-Id 不是一个 id |
| 401 | bearer 令牌缺失、无效、过期、已吊销,或者把 API 密钥用在了账户端点上 |
| 402 | 组织的余额已经没了 |
| 403 | 你通过了认证但没有权限:仅限管理员的操作、组织不对,或者对象不可修改 |
| 404 | 不存在,或者你的组织看不到——这两者是故意做成无法区分的 |
| 409 | 状态冲突:报价被人抢走、实例处在错误的状态、名称已被占用 |
| 422 | 取值不对:字段超出范围、磁盘比机器还大、枚举值未知 |
租用方真正会撞上的
| 情形 | 状态码 | 代码 | 该怎么办 |
|---|---|---|---|
| 余额为空时部署或启动 | 402 | INSUFFICIENT_BALANCE | 由管理员在控制台里添加余额。响应体里带着 balance_microusd 和 required_microusd。API 密钥不能充值。 |
| 在你的列表调用和部署之间,报价被人租走了 | 409 | OFFER_UNAVAILABLE | 从你筛出的列表里取下一份报价重试。不要用同一个 offer_id 重试。 |
| 这台机器被安排下线的时间,比启动一个实例所需的时间还早 | 409 | MACHINE_IN_MAINTENANCE | 响应体中带有 next_maintenance。换台机器部署,或等这段窗口过去。这不是容量问题——机器上还有空闲 GPU——所以窗口结束后用同一份报价重试是可以的。 |
disk_gb 不在 10–20000 之内 | 422 | 校验错误列表 | 发一个落在范围内的值 |
disk_gb 比主机的磁盘还大 | 422 | DISK_TOO_LARGE | 响应体里带着 max_disk_gb。按不超过它的值重试,或者换一台更大的机器。 |
| 仅限管理员的操作,或者用 API 密钥去做任何管理员操作 | 403 | ADMIN_REQUIRED | 改用属于管理员的会话令牌。结账、邀请和成员管理永远不对密钥开放。见角色与权限。 |
| 吊销一个未知的、已经吊销的,或属于别的组织的密钥 | 404 | API_KEY_NOT_FOUND | 重新调 GET /v1/api-keys 列一遍,用当前的 id |
| 从一个不允许的状态去停止、启动或销毁 | 409 | INVALID_STATE | 先读一下 status。消息里会点明当前那个状态,例如 Cannot start an instance while it is running。 |
在不支持虚拟机的机器上用 vm 模板 | 422 | OFFER_NOT_VM_CAPABLE | 筛出 vm_capable 为 true 的报价 |
ssh_key_id 不在你的账户上 | 404 | SSH_KEY_NOT_FOUND | 用会话令牌调 GET /v1/ssh-keys 列一遍,从中挑一个 id |
| 你的组织看不到的实例、报价或模板 | 404 | INSTANCE_NOT_FOUND, OFFER_NOT_FOUND, TEMPLATE_NOT_FOUND | 检查你发的 X-Org-Id,以及那个对象是否还在 |
认证和组织相关的失败——TOKEN_INVALID、TOKEN_EXPIRED、NOT_A_MEMBER、ORG_MISMATCH、INVALID_ORG_ID——在身份认证里讲。完整的代码清单见错误代码。
重试
| 响应 | 要重试吗? |
|---|---|
| 402 | 不。在余额到账之前,什么都不会变。 |
409 OFFER_UNAVAILABLE | 要,换一份报价。 |
409 MACHINE_IN_MAINTENANCE | 要,换一台机器;或者等过了 next_maintenance 再用同一台。 |
409 INVALID_STATE | 只有在重新读取实例、确认这次状态转换现在合法之后才行。 |
| 422 | 不。先把请求改对。 |
401 TOKEN_EXPIRED | 要,用新的会话令牌重试一次。shk_ 密钥不会过期,所以密钥上出现 401 就意味着它被吊销了。 |
POST /v1/instances 不接受幂等键,所以一旦超时,你就不知道这次租用到底成没成。**去查,而不是去重试:**调 GET /v1/instances,按你的 label 比对。
用同一个 offer_id 重试不安全。一份报价是一种规格,不是一个独占名额 —— 只要那台机器还有空余 GPU,同一份报价就会再被满足一次,你会拿到第二个实例、单独计费,而你本来只想部署一次。只有当那台机器的份额已经用光时它才会返回 409,而那恰恰是你本来就不会被重复扣费的情况。