Errors
Every failure is an RFC 9457 problem document. The code is the
stable part — branch on it, never on the prose.
HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
{
"type": "https://api.goterrago.com/errors/otp_undeliverable",
"code": "otp_undeliverable",
"title": "No phone on this account",
"status": 422,
"detail": "This account has no phone number, so a sign-in code cannot be sent to it.",
"request_id": "ceed5aee17b88eaff48b83181e85bb85"
}
request_id is echoed on every response, successful or not. Quote it in a
support conversation and the whole request can be found in the logs.
Catalog
Scanned from the call sites that raise them, so a code that is no longer raised is no longer listed. Sites counts how many places in the application raise it — a high count usually means a generic code used across many resources.
| Code | Title | Status | Sites |
|---|---|---|---|
account_inactive | This account is no longer active | 401 | 3 |
account_not_allowed | Do not name an account | 422 | 1 |
account_not_found | No account to credit this code to | 404 | 8 |
account_required | Name the guardian | 422 | 1 |
already_set_password | This person has already set their password — reset it instead | 422 | 1 |
audience_too_large | The selector matched more than 500 students — narrow it | 422 | 1 |
band_has_no_wearer | Nobody is wearing that band | 422 | 1 |
band_has_wearer | Band is worn | 422 | 3 |
band_reserved | Band is reserved for another event | 422 | 1 |
band_retired | Band is retired | 422 | 1 |
band_type_in_use | Band type is in use | 409 | 1 |
band_type_name_taken | Band type name already used | 409 | 2 |
band_unallocated | Band is in the platform stock pool | 422 | 2 |
batch_write_forbidden | Writes are not batchable | 405 | 1 |
below_withdraw_minimum | That is below the smallest withdrawal we can send | 422 | 2 |
cadence_not_available | That report cannot run on that schedule | 422 | 1 |
cannot_remove_yourself | You cannot remove your own account | 422 | 1 |
capacity_exceeded | This school has reached its student capacity | 422 | 2 |
client_not_found | No such API client | 404 | 2 |
code | Title | 422 | 1 |
code_in_use | That short code belongs to another school | 409 | 2 |
conflict | Category save conflict | 409 | 6 |
currency_mismatch | Currency does not match the catalog | 422 | 5 |
day_required | Choose which day of the week this digest goes out | 422 | 2 |
device_blocked | This device has been blocked | 403 | 3 |
device_header_required | Terra-Device-Fingerprint and Terra-Device-Serial headers are required on this surface | 400 | 1 |
device_mismatch | Token was not issued to this device | 401 | 1 |
device_not_found | Device not found | 404 | 4 |
digest_not_found | Digest not found | 404 | 3 |
empty_audience | The selector matched no students | 422 | 2 |
empty_list | There was nothing to read | 422 | 1 |
endpoint_inactive | Endpoint is not active | 422 | 1 |
event_ambiguous | Say which event this top-up is for | 422 | 1 |
event_not_held | You do not hold a ticket to that event | 422 | 1 |
exceeds_outstanding | Repayment exceeds the outstanding balance | 422 | 1 |
export_not_found | Export not found | 404 | 2 |
forbidden | Invalid webhook token | 403 | 22 |
gateway_unavailable | Withdrawals are not available yet | 503 | 1 |
group_name_in_use | A group with that name already exists | 409 | 2 |
group_not_found | School group not found | 404 | 2 |
guardian_has_no_login | This parent has no login yet | 422 | 1 |
guardian_not_found | Guardian not found | 404 | 2 |
guardian_not_linked | This guardian is not linked to the student | 404 | 1 |
home_location_not_found | Home location not found | 404 | 3 |
illegal_trip_transition | Illegal trip transition | 409 | 2 |
insufficient_funds | Payment refused | 422 | 9 |
intelligence_unavailable | — | varies | 1 |
invalid_client | Those client credentials were refused | 401 | 1 |
invalid_image | Invalid image | 400 | 1 |
invalid_pickup_code | Invalid or expired pickup code | 404 | 2 |
invalid_replacement_reason | A replacement is for a lost or damaged band | 422 | 1 |
invalid_state_transition | Band is not assignable | 422 | 7 |
invalid_trip | Invalid trip | 422 | 1 |
invalid_zones | — | varies | 2 |
invite_identity_taken | — | varies | 1 |
invite_invalid | That invitation is not valid any more | 410 | 1 |
invite_needs_guardians | An app invite takes the guardian_ids selector only | 422 | 1 |
invoice_not_found | Invoice not found | 404 | 1 |
invoice_not_payable | Invoice is not payable | 422 | 1 |
last_admin | This is the school's only administrator — add another before removing this one | 422 | 1 |
link_not_found | Link not found | 404 | 2 |
loan_not_active | The loan is not active | 409 | 1 |
log_not_found | Service log not found | 404 | 1 |
malformed_encoding | Body is not valid gzip | 400 | 1 |
missing_capability | You do not have the capability this action requires | 403 | 4 |
ml_unavailable | The optimizer is unavailable right now | 404 | 2 |
name_in_use | A category with this name already exists | 409 | 3 |
no_devices | None of those devices are yours to move | 422 | 1 |
no_open_shift | No shift is running on this event | 404 | 1 |
no_payout_destination | Add and verify a phone number before withdrawing | 409 | 1 |
no_sim | The device has no SIM msisdn on record | 422 | 1 |
not_a_guardian | Not a guardian | 403 | 2 |
not_a_platform_operator | Only a platform operator can view a school in shadow mode. | 403 | 1 |
not_enough_stops | Not enough students with a captured home location to suggest a route assignment | 404 | 2 |
not_found | Unknown zone | 404 | 71 |
not_refundable | This transaction kind cannot be refunded | 409 | 1 |
not_shareable | Not shareable by this principal | 403 | 1 |
not_trip_driver | Not the trip driver | 403 | 5 |
not_undoable | This event cannot be undone | 409 | 1 |
not_your_shift | This shift belongs to another steward | 403 | 2 |
operator_has_no_tenant_scope | A platform operator already sees every school; switching would narrow that. | 409 | 1 |
otp_invalid | That code is wrong or has expired | 401 | 4 |
otp_undeliverable | No phone on this account | 422 | 1 |
overloaded | The service is at its concurrency limit; retry shortly | varies | 2 |
parser_failed | The list could not be read | 502 | 1 |
parser_unavailable | List reading is switched off | 503 | 1 |
payload_not_retained | Nothing left to send | 422 | 1 |
payload_too_large | Compressed body exceeds 1 MB | 413 | 2 |
phone_in_use | Phone already registered | 409 | 4 |
pin_required | A PIN is required to set one | 422 | 1 |
policy_exceeded | Policy exceeded | 422 | 1 |
preferences_too_large | The preference document is too large | 422 | 1 |
presence_conflict | The subject is checked in elsewhere | 409 | 1 |
profile_in_use | Unassign the profile from its wallets first | 409 | 1 |
recipient_not_found | Those recipients are not on this school's roster | 422 | 1 |
refresh_token_reused | Refresh token reuse detected — session revoked | 401 | 1 |
replacement_not_in_stock | The replacement is already issued to somebody | 409 | 1 |
role_in_use | Reassign this role's users first | 409 | 1 |
role_name_taken | A role with this name already exists | 422 | 1 |
role_not_found | Unknown role | 404 | 2 |
route_not_found | Route not found | 404 | 3 |
school_not_found | School not found | 404 | 8 |
school_not_permitted | You do not have access to that school. | 403 | 1 |
school_required | Choose which school this parent belongs to. | 422 | 1 |
serial_in_use | Serial already registered | 409 | 2 |
session_already_closed | Undo the check-out first | 409 | 1 |
session_revoked | This session has ended — sign in again | 401 | 1 |
settings_not_found | Notification settings not found | 404 | 1 |
setup_incomplete | School setup is not finished | 422 | 1 |
shadow_session_cannot_switch | Leave shadow mode before switching schools. | 409 | 1 |
shift_closed | This shift has already been closed | 409 | 1 |
sku_in_use | An item with this SKU already exists | 409 | 2 |
spending_profile_empty | That profile sets no limits | 422 | 1 |
stale_version | The row moved since you read it — refetch, re-apply, retry | 409 | 14 |
student_not_found | Student not found | 404 | 12 |
survey_not_active | Survey is not active | 409 | 1 |
survey_not_draft | Survey is not a draft | 409 | 1 |
template_not_found | Template not found (platform templates are read-only here) | 404 | 1 |
template_provider_failed | WhatsApp template provider refused | 502 | 1 |
tenant_not_permitted | You do not have access to that school. | 403 | 2 |
tenant_required | Name the organizer this event belongs to | 422 | 5 |
ticket_already_claimed | This seat already has a real holder | 409 | 1 |
ticket_already_redeemed | Somebody has already walked in on this ticket | 409 | 1 |
ticket_not_transferable | Only an issued ticket can change hands | 422 | 1 |
ticketing_invalid_key | — | varies | 1 |
ticketing_not_connected | No ticketing integration is connected | 404 | 4 |
ticketing_sync_failed | — | varies | 1 |
ticketing_webhook_failed | — | varies | 1 |
trip_not_found | Trip not found | 404 | 14 |
trip_not_replayable | A trip can only be replayed after it ends | 409 | 3 |
trip_plan_not_found | Trip plan not found | 404 | 1 |
trip_replay_empty | This trip synced no GPS points | 404 | 1 |
trip_route_comparison_unavailable | Not enough data to compare this trip to an optimal plan | 404 | 1 |
trip_route_segments_unavailable | Not enough data to build a segment-by-segment comparison for this trip | 404 | 1 |
unauthenticated | Invalid credentials | 401 | 5 |
undo_window_elapsed | The undo window has elapsed | 422 | 1 |
unknown_band | Unknown band | 404 | 7 |
unknown_band_type | Unknown band type | 404 | 5 |
unknown_beneficiary | Unknown beneficiary | 422 | 1 |
unknown_category | Unknown category | 422 | 2 |
unknown_event | Event not found on that organizer | 404 | 1 |
unknown_gateway | Unknown payment gateway | 422 | 2 |
unknown_organizer | Unknown organizer | 404 | 2 |
unknown_replacement_band | The replacement serial is not registered here | 404 | 1 |
unknown_report | That report cannot be scheduled | 422 | 1 |
unknown_role | The role does not exist in this tenant | 422 | 1 |
unknown_school | School not found | 404 | 6 |
unknown_spending_profile | Unknown spending profile | 422 | 1 |
unknown_stop | One or more stops do not belong to this plan's route | 422 | 1 |
unknown_student | One or more students do not exist in this tenant | 422 | 1 |
unknown_template | Unknown template | 422 | 2 |
unknown_wallet_type | Unknown wallet type | 422 | 3 |
unknown_zone | Zone not found in this tenant | 422 | 3 |
unsupported_encoding | Only Content-Encoding: gzip is supported on this endpoint | 415 | 1 |
user_has_no_email | This person has no email address — add one before inviting them | 422 | 1 |
user_not_found | User not found | 404 | 6 |
validation_failed | students must name 1– | 422 | 22 |
vehicle_capacity_missing | No buses have a seat capacity on file — set capacities before suggesting a route assignment | 422 | 1 |
vehicle_fields_required | Capacity, fuel type, and fuel consumption are required when adding a new bus | 422 | 1 |
vehicle_on_trip | Vehicle already on a trip | 409 | 1 |
voucher_invalid | Voucher invalid | 422 | 1 |
voucher_redeemed | Voucher already redeemed | 409 | 2 |
voucher_unfunded | Voucher cannot be honored | 422 | 1 |
wallet_has_balance | Refund or transfer the wallet balance before removing this learner | 422 | 1 |
wallet_has_transactions | This learner has spending history — close the wallet before removing them | 422 | 1 |
wallet_not_found | Wallet not found | 404 | 17 |
wallet_unavailable | This event cannot take top-ups yet | 409 | 2 |
wallet_unresolvable | No wallet could be derived for the wearer | 422 | 2 |
wallet_wearer_mismatch | Wallet does not belong to the wearer | 422 | 1 |
zone_not_assigned | This zone is not assigned to you | 403 | 1 |
zone_not_found | Zone not found | 404 | 4 |
zone_required | Name the gate — this school has more than one | 422 | 1 |