FriendChise Docs

Error Handling

HTTP status codes, error response shape, and common errors across all API routes

Error response shape

All error responses return JSON with an error string:

{
  "error": "Descriptive error message."
}

Field-level validation errors include an errors map alongside error:

{
  "error": "Invalid task data",
  "errors": {
    "title": ["String must contain at least 1 character(s)"],
    "durationMin": ["Number must be greater than 0"]
  }
}

Successful responses do not include an error field.

HTTP status codes

StatusMeaningWhen you'll see it
200 OKRequest succeededMost GET and some POST requests
201 CreatedResource was createdTask creation (POST /api/orgs/[orgId]/tasks)
400 Bad RequestMissing or invalid inputValidation failures, malformed body, invalid query params
401 UnauthorizedAuthentication requiredNo session, expired or missing bearer token
403 ForbiddenAuthenticated but not permittedInsufficient org role, wrong franchise scope
404 Not FoundResource does not existTask, org, image, or user not found
409 ConflictDuplicate resourceTask with the same name already exists in the org
429 Too Many RequestsRate/demo limit hitDemo account task limit reached
500 Internal Server ErrorUnexpected server failureDatabase error, storage error, or unhandled exception

Common error messages

MessageStatusExplanation
"Unauthorized"401Bearer token missing, expired, or invalid
"Forbidden"403User lacks the required org permission
"User not found"404Authenticated user ID has no database record
"Organization not found"404orgId path param does not match any org
"Task not found"404taskId does not exist or is not accessible
"A task named "..." already exists."409Title collision within the org
"Confirmation text is required"400Account delete request missing confirmText
"Confirmation text does not match"400confirmText does not match the user's display name when available, otherwise their email
"Invalid kind"400kind query param not one of conversion, item-list, roster
"mimeType is required."400Image upload-url request missing mimeType body field
"storagePath is required."400Storage read-url request missing storagePath body field
"Failed to create task."500Unexpected error during task creation
"Failed to load scan history."500Unexpected error loading scan-to-task results

Authentication errors

Unauthenticated requests to protected routes return:

{ "error": "Unauthorized" }

with status 401. A few routes (for example GET /api/me/organizations) return an empty result set instead of a 401 when no session is present.

Validation errors

Routes that use Zod validation return the flattened field errors under errors:

{
  "error": "Invalid task data",
  "errors": {
    "title": ["Required"],
    "durationMin": ["Number must be positive"]
  }
}

Each key in errors is a field name; each value is an array of one or more error strings.

Retrying after errors

  • 400 — Fix the request body or query params. Do not retry without changing the input.
  • 401 — Re-authenticate and retry with a fresh token.
  • 403 — The user does not have the required role in that org. Do not retry.
  • 404 — The resource does not exist. Do not retry without first confirming the resource exists.
  • 409 — Choose a different name and retry, or surface the conflict to the user.
  • 500 — Retry only idempotent reads by default. For writes, use idempotency keys when the route supports them, or reconcile the resource state before retrying a non-idempotent POST, PATCH, or DELETE.