错误处理
Img2Vid API 使用统一错误响应格式。
错误格式
{
"error": {
"code": "invalid_api_key",
"message": "Invalid or inactive API key.",
"details": {}
}
}
只有存在额外结构化信息时才会返回 details。
鉴权错误
| Code | HTTP | 含义 | 处理方式 |
|---|---|---|---|
missing_api_key |
401 | 未提供 API Key。 | 发送 Authorization: Bearer <key>。 |
invalid_api_key |
401 | API Key 无效、未激活或已删除。 | 检查或轮换 Key。 |
invalid_api_key_owner |
401 | Key 所属用户不存在。 | 使用有效账号重新创建 Key。 |
请求错误
| Code | HTTP | 含义 | 处理方式 |
|---|---|---|---|
invalid_request_body |
400 | JSON 请求体无效或字段类型不匹配。 | 校验请求字段和类型。 |
unsupported_field |
400 | 传入了嵌套结构或内部字段。 | 移除 input、options、scene、sub_mode_id、provider、media type 和内部媒体字段。 |
missing_file |
400 | 上传请求缺少 file 字段。 |
添加 file 表单字段。 |
模型与 mode 错误
| Code | HTTP | 含义 | 处理方式 |
|---|---|---|---|
model_not_found |
404 | 模型不可用。 | 使用 /api/v1/media_models 返回的模型 key。 |
model_not_api_configured |
422 | 模型没有公开 API 配置。 | 选择其他 API 可用模型。 |
mode_not_supported |
422 | 当前模型不存在该 mode。 | 使用 /api/v1/media_models 的 operations[].mode。 |
mode_not_api_configured |
422 | mode 存在但没有公开 endpoint。 | 使用列表中的其他 operation。 |
unsupported_input_for_model |
422 | 输入形态不受支持。 | 查看该模型 mode 的输入要求。 |
ambiguous_generation_mode |
422 | 输入同时匹配多个 mode。 | 显式传入 mode。 |
mode_scene_missing |
422 | mode 缺少内部场景映射。 | 联系支持,这是配置问题。 |
文件错误
| Code | HTTP | 含义 | 处理方式 |
|---|---|---|---|
unsupported_file_type |
415 | MIME 类型不是图片、视频或音频。 | 上传支持的媒体文件。 |
unsupported_file_format |
415 | 文件格式不被所选 mode 支持。 | 查看模型参考中的格式限制。 |
file_too_large |
413 | 文件超出大小限制。 | 压缩文件或选择限制更宽的 mode。 |
upload_failed |
502 | 存储上传失败。 | 重试,持续失败请联系支持。 |
unsupported_upload_target |
422 | 配置的上传目标不支持。 | 联系支持,这是配置问题。 |
SDK 错误处理
SDK 会把非 2xx API 响应转换为各语言原生的异常或错误值。轮询 helper 还可能返回超时、生成失败和生成取消相关错误。
下面的片段假设你已经按快速开始初始化了 SDK client,并引入了对应语言需要的 SDK 类型。
JavaScript / TypeScript
import { BubleAPIError } from '@buble/sdk';
try {
await buble.generations.retrieve('task_id');
} catch (error) {
if (error instanceof BubleAPIError) {
console.error(error.status, error.code, error.message, error.details);
}
}
Python
from buble_ai import BubleAPIError
try:
client.generations.retrieve("task_id")
except BubleAPIError as error:
print(error.status_code, error.code, error.message, error.details)
Go
_, err := client.Generations.Retrieve(ctx, "task_id")
if err != nil {
var apiErr *buble.APIError
if errors.As(err, &apiErr) {
fmt.Println(apiErr.StatusCode, apiErr.Code, apiErr.Message, apiErr.Details)
}
}
Rust
match client.generations().retrieve("task_id").await {
Err(buble::Error::Api(error)) => {
eprintln!("{} {:?} {}", error.status, error.code, error.message);
}
other => {
// Handle success or other SDK error variants.
}
}
Swift
do {
_ = try await client.generations.retrieve("task_id")
} catch BubleError.api(let error) {
print(error.statusCode)
print(error.code ?? "")
print(error.message)
}
Dart / Flutter
try {
await client.generations.retrieve('task_id');
} on BubleApiException catch (error) {
print(error.statusCode);
print(error.code);
print(error.message);
}
Elixir
case Buble.Generations.retrieve(client, "task_id") do
{:ok, task} ->
task
{:error, %Buble.Error{type: :api, status: status, message: message}} ->
IO.puts("Buble API error #{status}: #{message}")
end
Java
try {
client.generations().retrieve("task_id");
} catch (BubleApiException error) {
System.err.println(error.getStatusCode());
System.err.println(error.getCode());
System.err.println(error.getMessage());
System.err.println(error.getDetails());
}
.NET
try
{
await client.Generations.RetrieveAsync("task_id");
}
catch (BubleApiException error)
{
Console.Error.WriteLine(error.StatusCode);
Console.Error.WriteLine(error.Code);
Console.Error.WriteLine(error.Message);
Console.Error.WriteLine(error.Details);
}
PHP
use Buble\Exception\ApiException;
try {
$client->generations()->retrieve('task_id');
} catch (ApiException $error) {
echo $error->statusCode . PHP_EOL;
echo $error->apiCode . PHP_EOL;
echo $error->getMessage() . PHP_EOL;
print_r($error->details);
}
Ruby
begin
client.generations.retrieve("task_id")
rescue Buble::APIError => error
warn error.status
warn error.code
warn error.message
warn error.details
end