Lỗi
Định dạng lỗi, mọi mã trạng thái và code mà API trả về, lỗi nào nên thử lại, và một hàm xử lý lỗi Node bạn có thể sao chép ngay.
Cập nhật
Khi một request thất bại, API trả về mã trạng thái 4xx hoặc 5xx và một body JSON với code ổn định. Hãy rẽ nhánh theo code. Nội dung error dành cho con người và có thể thay đổi.
Định dạng
{
"error": "This API key doesn't have the earnings:read scope.",
"code": "insufficient_scope",
"scope": "earnings:read"
}
| Trường | Luôn có | Ý nghĩa |
|---|---|---|
error |
Có | Mô tả sự cố bằng lời. Có thể ghi log hoặc hiển thị cho người vận hành. |
code |
Có | Một code ổn định. Xem các bảng bên dưới. |
field |
Khi là invalid |
Parameter hoặc trường trong body gây lỗi. |
scope |
Khi là insufficient_scope |
Scope mà key cần có. |
Một vài lỗi có thêm trường riêng. Ví dụ, 409 upload_incomplete liệt kê các phần missing và wrong_size.
Lỗi mà mọi endpoint đều có thể trả về
| Mã trạng thái | code |
Ý nghĩa | Thử lại? |
|---|---|---|---|
| 400 | invalid |
Một parameter bị sai. field cho biết parameter nào. |
Không. Hãy sửa request. |
| 401 | unauthenticated |
Không có header Authorization: Bearer. |
Không |
| 401 | invalid_key |
Key không tồn tại. | Không |
| 401 | key_revoked |
Key đã bị thu hồi. Hãy tạo key mới. | Không |
| 401 | key_expired |
Key đã hết hạn. Hãy tạo key mới. | Không |
| 401 | test_keys_retired |
Một key hm_test_, đã ngừng sử dụng từ 12/10/2026. Hãy dùng key hm_live_. |
Không |
| 403 | insufficient_scope |
Key thiếu scope mà endpoint này cần. scope cho biết scope nào. |
Không |
| 403 | account_inactive |
Tài khoản của bạn không hoạt động. | Không |
| 403 | api_not_in_plan |
Gói của bạn không bao gồm API. API đi kèm Enterprise và Custom. | Không |
| 404 | not_found |
Không có endpoint này, hoặc đối tượng không thuộc về bạn. | Không |
| 429 | rate_limited |
Vượt giới hạn mỗi phút của key này. | Có, sau Retry-After giây |
| 500 | server_error |
Có sự cố ở phía chúng tôi. | Có, với backoff |
404 not_found bao gồm cả trường hợp “không tồn tại” lẫn “thuộc về tài khoản khác”. API không bao giờ cho bạn biết một bản phát hành của người khác có tồn tại hay không.
Lỗi của từng endpoint cụ thể
| Mã trạng thái | code |
Ở đâu | Ý nghĩa |
|---|---|---|---|
| 409 | exists |
POST /members/invite |
Đã có tài khoản với email này. |
| 413 | too_large |
POST /ddex/validate |
Lớn hơn mức một lần kiểm thử nhận được. Hãy phân phối bằng POST /ddex. |
| 413 | too_large |
POST /ddex |
Quá 20 GB (body thô) hoặc 512 MB (multipart). Hãy dùng tải lên trực tiếp. |
| 429 | busy |
POST /ddex/validate |
Quá nhiều lần kiểm thử cùng lúc. Hãy thử lại sau ít phút. |
| 409 | upload_incomplete |
POST /ddex/uploads/{id}/commit |
Thiếu phần hoặc phần sai kích thước. Hãy tải chúng lên, rồi commit lại. |
| 409 | already_committed |
Tải lên trực tiếp | Đã commit trước đó. status_url trỏ đến lần phân phối. |
| 409 | commit_in_progress |
POST /ddex/uploads/{id}/commit |
Một lần commit khác của bản tải lên này đang chạy. |
| 400 | invalid_url |
POST /webhooks, PATCH /webhooks/{id} |
Không phải URL https công khai trên cổng 443. |
| 409 | too_many |
POST /webhooks |
Bạn đã có 20 endpoint. |
| 409 | endpoint_disabled |
Gửi test và gửi lại webhook | Endpoint đang tắt. Hãy bật nó trước. |
Mỗi trang tham chiếu liệt kê lỗi của từng endpoint. Scope và lỗi có các lỗi dùng chung.
Lỗi kiểm tra dữ liệu
Một lỗi 400 invalid nêu vấn đề đầu tiên mà API tìm thấy:
{
"error": "updated_since is an ISO date or time.",
"code": "invalid",
"field": "updated_since"
}
Mỗi lần chỉ báo một trường. Hãy sửa rồi gửi lại. Nếu bạn xây dựng biểu mẫu trên API, hãy hiển thị error cạnh ô nhập được nêu trong field.
Tệp DDEX thì khác. Một lô DDEX có vấn đề không phải là lỗi 400. Lần kiểm thử trả về 200 với mọi bước kiểm tra và một kết luận, còn một lần phân phối trả về 202 và báo vấn đề theo từng bản phát hành. Xem Phân phối DDEX.
Nên thử lại lỗi nào
- Thử lại
429và5xx, cùng các lỗi mạng như timeout và reset. - Không thử lại các lỗi
4xxkhác. Cùng một request sẽ nhận cùng một phản hồi. Hãy sửa request, key hoặc scope của key trước.
Với 429, hãy chờ số giây ghi trong Retry-After. Với 5xx, hãy chờ lâu hơn sau mỗi lần thử (1 giây, 2 giây, 4 giây…) và dừng lại sau vài lần. Xem Rate limit.
Thao tác đọc có thể thử lại an toàn. Hãy cân nhắc trước khi thử lại một thao tác ghi. Gửi lại POST /ddex sau khi mất phản hồi có thể đưa lô vào hàng đợi hai lần. Hãy kiểm tra GET /ddex trước.
Hàm xử lý lỗi cho Node
export class HillsError extends Error {
constructor(status, body, headers) {
super(body.error ?? `HTTP ${status}`);
this.status = status;
this.code = body.code;
this.field = body.field;
this.scope = body.scope;
this.retryAfter = Number(headers.get("Retry-After")) || null;
}
}
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
export async function hills(path, init = {}, tries = 4) {
for (let i = 1; ; i++) {
const res = await fetch("https://api.hillsmusic.com/v1" + path, {
...init,
headers: { ...init.headers, Authorization: `Bearer ${process.env.HILLS_API_KEY}` },
});
const body = await res.json().catch(() => ({}));
if (res.ok) return body;
const err = new HillsError(res.status, body, res.headers);
const retryable = res.status === 429 || res.status >= 500;
if (!retryable || i >= tries) throw err;
await sleep(err.retryAfter ? err.retryAfter * 1000 : 1000 * 2 ** (i - 1));
}
}
try {
await hills("/earnings");
} catch (err) {
if (err.code === "insufficient_scope") console.error(`Add ${err.scope} to this key.`);
else if (err.code === "api_not_in_plan") console.error("The plan doesn't include the API.");
else throw err;
}
Với curl, thêm -w '%{http_code}' để xem mã trạng thái, hoặc -i để xem các header:
curl -i "https://api.hillsmusic.com/v1/releases/999999" \
-H "Authorization: Bearer $HILLS_API_KEY"
# HTTP/2 404
# {"error":"…","code":"not_found"}