Error reference
Nines follows RFC 7807 — Problem Details for HTTP APIs. Error responses use the application/problem+json media type and include a type URI that dereferences to this page. Each section below documents one problem type: when it fires, the shape of the response, and how clients should recover.
Bad request
When it fires
The request body is unparseable, a required query parameter is missing or malformed, or the Content-Type does not match what the endpoint expects.
Example response
{
"type": "https://nines.sh/docs/errors#bad_request",
"title": "Bad request",
"status": 400,
"detail": "invalid JSON body",
"instance": "/settings/api-keys"
}
Client recovery
Inspect the detail field. Fix the client — for example, send valid JSON, include the required query parameter, or set the correct Content-Type — and retry.
Validation failed
When it fires
One or more field values failed business-rule validation (e.g., required field omitted, value out of range, invalid format).
Errors array
The errors array contains one entry per offending field with the field name, a machine-readable code (e.g., required, too_low, invalid_url), and a human-readable message.
Example response
{
"type": "https://nines.sh/docs/errors#validation",
"title": "Invalid request",
"status": 422,
"detail": "One or more fields failed validation",
"instance": "/settings/api-keys",
"errors": [
{"field": "name", "code": "required", "message": "name is required"}
]
}
Client recovery
Iterate the errors array, map each field back to its form input, and present the message to the user. Resubmit once the fields are corrected.
Forbidden
When it fires
The caller is authenticated but lacks permission to perform this action on this resource (e.g., editing a monitor owned by another organization).
Example response
{
"type": "https://nines.sh/docs/errors#forbidden",
"title": "Forbidden",
"status": 403,
"detail": "you cannot modify this monitor",
"instance": "/monitors/abc123"
}
Client recovery
Show the detail message to the user. This is not a retryable error — the client should not attempt the same operation again with the same credentials.
Not found
When it fires
The requested resource (monitor, incident, API key, etc.) does not exist, or has been deleted, or is owned by a different organization.
Example response
{
"type": "https://nines.sh/docs/errors#not_found",
"title": "Not found",
"status": 404,
"detail": "monitor not found",
"instance": "/monitors/abc123"
}
Client recovery
Remove the resource from the client-side list or cache, then return the user to a valid view (index, dashboard, etc.).
Conflict
When it fires
The request collides with existing state — for example, the slug is already taken, the email is already registered, or the resource was modified concurrently.
Example response
{
"type": "https://nines.sh/docs/errors#conflict",
"title": "Conflict",
"status": 409,
"detail": "email already in use",
"instance": "/register"
}
Client recovery
Show the detail message to the user. If the conflict is correctable (e.g., pick a different slug), prompt for a new value and retry; otherwise surface the error.
Quota exceeded
When it fires
The operation would exceed a plan-based limit — for example, creating more monitors than the current plan allows, or using features gated behind a higher tier.
Example response
{
"type": "https://nines.sh/docs/errors#quota_exceeded",
"title": "Quota exceeded",
"status": 403,
"detail": "monitor limit reached for the Free plan",
"instance": "/monitors"
}
Client recovery
Offer the user a path to upgrade their plan, or free up capacity by removing existing resources. Do not retry — the limit will still be in effect.
Too many requests
When it fires
The caller exceeded a per-IP or per-user rate limit (for example, too many password reset requests in a short window). Applies equally to HTML and JSON clients.
Example response
{
"type": "https://nines.sh/docs/errors#too_many_requests",
"title": "Too many requests",
"status": 429,
"detail": "Too many password reset requests. Please wait and try again.",
"instance": "/forgot-password"
}
Client recovery
Back off and retry later. Clients should respect the rate limit — hammering the endpoint will continue to fail.
Payload too large
When it fires
The request body exceeds the per-endpoint size limit (for example, posting more than 256 KB to the worker check-result ingest endpoint or more than 64 KB to a JSON CRUD endpoint).
Example response
{
"type": "https://nines.sh/docs/errors#payload_too_large",
"title": "Payload too large",
"status": 413,
"detail": "request body exceeds the 65536-byte limit for this endpoint",
"instance": "/api/v1/notification-channels"
}
Client recovery
Trim the payload to fit the documented limit. The detail field reports the exact byte cap; do not retry the same body — it will keep failing.
Internal server error
When it fires
An unexpected server-side failure (database outage, bug, exhausted resources). The root cause is intentionally not surfaced to clients to avoid leaking internals.
Example response
{
"type": "https://nines.sh/docs/errors#internal",
"title": "Internal server error",
"status": 500,
"detail": "The server encountered an unexpected error",
"instance": "/monitors"
}
Client recovery
Retry the request after a short backoff (1s, 2s, 4s). If it continues to fail, surface a generic error to the user and alert your team. Nines also logs these server-side with a trace id.
Slow down
When it fires
RFC 8628 device-code flow: the CLI polled POST /oauth/token faster than the advertised interval.
Example response
{
"type": "https://nines.sh/docs/errors#device_slow_down",
"title": "slow_down",
"status": 400,
"detail": "polling too fast; slow down",
"instance": "/oauth/token"
}
Client recovery
Increase the poll interval by at least 5 seconds and continue polling. Repeated slow_down responses indicate the client must back off further.
Device token expired
When it fires
RFC 8628 device-code flow: the device_code expired before the user approved, or it has already been exchanged once.
Example response
{
"type": "https://nines.sh/docs/errors#device_expired_token",
"title": "expired_token",
"status": 400,
"detail": "device_code has expired",
"instance": "/oauth/token"
}
Client recovery
Restart the flow: request a new device_code via POST /oauth/device/code and prompt the user again.
Device access denied
When it fires
RFC 8628 device-code flow: the user clicked Deny on the approval page.
Example response
{
"type": "https://nines.sh/docs/errors#device_access_denied",
"title": "access_denied",
"status": 400,
"detail": "the user denied the authorization request",
"instance": "/oauth/token"
}
Client recovery
Stop polling. Prompt the user to try again from the start if they changed their mind.
Device invalid grant
When it fires
RFC 8628 device-code flow: the token request is missing device_code or grant_type is not urn:ietf:params:oauth:grant-type:device_code.
Example response
{
"type": "https://nines.sh/docs/errors#device_invalid_grant",
"title": "invalid_request",
"status": 400,
"detail": "device_code is required",
"instance": "/oauth/token"
}
Client recovery
Fix the request body. grant_type must be the RFC 8628 URN and device_code must be a non-empty string returned from POST /oauth/device/code.
Need more help? Contact support or head back to the main documentation.