Skip to content

Error Codes

All club API errors follow a single JSON envelope. This page documents the shape, the codes that appear in it, and when each one occurs.

Error Envelope

Every error response contains an error object with a code and a human-readable message:

{
"error": {
"code": "NotFound",
"message": "Package 'nonexistent' was not found."
}
}
FieldTypeDescription
error.codestringMachine-readable error code (PascalCase)
error.messagestringHuman-readable description

The code field is stable and safe for programmatic error handling. Messages may change between versions — use them for display only.


Common Error Codes

CodeHTTP StatusWhen
MissingAuthentication401No credentials provided, or bad email/password, or invalid/expired/revoked token
InsufficientPermissions403Authenticated but lacking the required role or scope
CsrfMismatch403Cookie-authenticated state-changing request with a missing or invalid CSRF token
NotFound404Resource does not exist
InvalidInput400Malformed input or validation failure
PackageRejected400Package upload failed validation (bad archive, name, version, or size)
Conflict409Resource already exists, or conflicting state (e.g. duplicate version with different content)
RateLimitExceeded429Too many requests from this IP
VerificationTemporarilyUnavailable503DNS verification could not complete due to a transient failure
InternalError500Unexpected server error

Examples

MissingAuthentication (401)

Sent when an endpoint requires authentication but none was provided. The same code is also returned by POST /api/auth/login for a bad email or password, and by any endpoint when the Bearer token is invalid, expired, or revoked (only the message differs).

{
"error": {
"code": "MissingAuthentication",
"message": "Authentication required."
}
}
{
"error": {
"code": "MissingAuthentication",
"message": "Invalid email or password."
}
}

Response headers on a 401 include:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="pub", message="Authentication required."

InsufficientPermissions (403)

Returned when the caller is authenticated but the operation requires a higher role, scope, or relationship to the resource.

{
"error": {
"code": "InsufficientPermissions",
"message": "Admin privileges required."
}
}

Common causes: token lacks the write or admin scope; user is not an uploader of the package; user is not a publisher admin; only the server owner can transfer ownership.

NotFound (404)

{
"error": {
"code": "NotFound",
"message": "Package 'nonexistent' was not found."
}
}

InvalidInput (400)

Used for malformed input and validation errors across the API.

{
"error": {
"code": "InvalidInput",
"message": "Cannot remove the last uploader."
}
}

PackageRejected (400)

Returned when a package upload fails validation during the finalize step.

{
"error": {
"code": "PackageRejected",
"message": "'My-Package' is not a valid package name. Package names must be lowercase, start with a letter, and contain only letters, numbers, and underscores."
}
}

Conflict (409)

{
"error": {
"code": "Conflict",
"message": "A user with that email already exists."
}
}
{
"error": {
"code": "Conflict",
"message": "Version is already retracted."
}
}

RateLimitExceeded (429)

Returned from rate-limited endpoints (/api/auth/login, /api/auth/signup, /api/setup/verify, /api/setup/complete, /api/invites/*). See the overview for per-endpoint limits.

{
"error": {
"code": "RateLimitExceeded",
"message": "Too many requests. Try again later."
}
}

InternalError (500)

Unexpected server error. Stack traces and internal details are never returned; check the server logs for diagnostics.

{
"error": {
"code": "InternalError",
"message": "An unexpected error occurred."
}
}

HTTP Status Summary

StatusMeaningTypical cause
200OKSuccessful GET, PUT, DELETE, idempotent POST
201CreatedSuccessful resource-creating POST
202AcceptedAsync acceptance (e.g. signup)
302FoundUpload-flow redirect; public archive served via external storage
303See OtherLegacy archive URL redirect
400Bad RequestInvalidInput, PackageRejected
401UnauthorizedMissingAuthentication
403ForbiddenInsufficientPermissions, CsrfMismatch
404Not FoundNotFound
409ConflictConflict
429Too Many RequestsRateLimitExceeded
500Internal Server ErrorInternalError
503Service UnavailableVerificationTemporarilyUnavailable, or health check reports degraded status