UnmarkdownDocs

Error Handling

Understand the Unmarkdown API error response format, all error codes, and retry strategies with code examples.

Error Response Format

All API errors return a JSON response body with a consistent structure. The response includes an error object containing a machine-readable code, a human-readable message, and the HTTP status.

json
{
  "error": {
    "code": "unauthorized",
    "message": "Invalid or missing API key",
    "status": 401
  }
}

The code field is a stable string identifier for use in your error handling logic. The message field may change over time, so do not rely on exact message text.

Error Codes

The complete list of error codes returned by the API:

  • invalid_body (400): Request body is malformed or not valid JSON
  • validation_error (400): Required field missing or field value invalid
  • unauthorized (401): API key is missing, invalid, or revoked
  • forbidden (403): Authenticated but not authorized (wrong account, Pro-only feature on Free)
  • not_found (404): Resource does not exist
  • conflict (409): Resource was modified since last read (optimistic locking)
  • quota_exceeded (429): Monthly API quota exceeded
  • rate_limited (429): Too many requests per second
  • internal_error (500): Unexpected server error
  • conversion_error (500): Markdown conversion pipeline failed
  • render_error (500): Template rendering failed

HTTP Status Codes

400 Bad Request

The request is malformed or missing required fields. Check the error message for which field is invalid.

401 Unauthorized

The API key is missing, invalid, or revoked. Verify your Authorization header.

403 Forbidden

Authenticated but not authorized. The resource belongs to another account, or the feature requires Pro.

404 Not Found

The requested resource does not exist. Verify the resource ID.

409 Conflict

The resource was modified since you last read it (optimistic locking). Re-fetch and retry.

429 Too Many Requests

Rate limit or monthly quota exceeded. Check the Retry-After header and the error code (rate_limited vs quota_exceeded).

500 Internal Server Error

Unexpected server error. Retry with exponential backoff.

Retry Logic

Use the status code to determine whether to retry:

  • 400, 401, 403, 404: Do not retry. Fix the request first.
  • 409: Re-fetch the resource, apply your changes, and retry.
  • 429 (rate_limited): Retry after the Retry-After header delay.
  • 429 (quota_exceeded): Do not retry until next month or upgrade.
  • 500: Retry with exponential backoff (max 3-5 attempts).

Error Handling (JavaScript)

javascript
async function apiCall(url, options) {
  const response = await fetch(url, options);

  if (response.ok) return response.json();

  const error = await response.json();

  switch (response.status) {
    case 429:
      if (error.error.code === "rate_limited") {
        const retryAfter = response.headers.get("Retry-After") || "1";
        await new Promise((r) => setTimeout(r, parseInt(retryAfter) * 1000));
        return apiCall(url, options); // retry once
      }
      throw new Error(`Quota exceeded: ${error.error.message}`);
    case 401:
      throw new Error("Invalid API key");
    default:
      throw new Error(`API error ${response.status}: ${error.error.message}`);
  }
}

Error Handling (Python)

python
import requests, time

def api_call(url, headers):
    response = requests.get(url, headers=headers)

    if response.ok:
        return response.json()

    error = response.json()["error"]

    if response.status_code == 429 and error["code"] == "rate_limited":
        retry_after = int(response.headers.get("Retry-After", "1"))
        time.sleep(retry_after)
        return api_call(url, headers)  # retry once

    if response.status_code == 401:
        raise Exception("Invalid API key")

    raise Exception(f"API error {response.status_code}: {error['message']}")

Common Errors

  • "The content field is required": Include a content field when creating documents
  • "Invalid API key": Check that the key starts with um_ and has not been revoked
  • "Quota exceeded": Wait for monthly reset or upgrade to Pro
  • "Document not found": Verify the document ID exists and belongs to your account
  • "Conflict detected": Re-fetch the document and retry with the latest version
Important
Always set a maximum number of retries (3 to 5 is typical) to prevent infinite retry loops.