Skip to main content

C2 — Error-to-UI Matrix

Scope: Every canonical error code in docs/standards/ERROR_CODES.md mapped to its frontend UI treatment. For each code: which UI pattern to use, whether to show retry, whether to escalate to an error page vs. inline toast vs. dialog, and which surface(s) it applies to.

How to use: When a BFF call returns an error.code field, look up that code below and render the mapped UI. All user-visible strings are resolved through the i18n bundle using the userMessageKey from ERROR_CODES.md; do not hard-code English strings.

Pattern definitions: see C3 — Empty/Loading/Error State Catalog.


1. UI pattern taxonomy

PatternWhen to useUser can retry?Dismissible?
Toast / snackbarTransient recoverable errors; non-blockingYes (auto-retry or CTA)Yes (auto-dismiss 5 s)
Inline field errorForm validation failure on a specific fieldN/AOn correction
Inline bannerSection-level warning that does not block the whole screenSometimesYes
Full-screen errorUnrecoverable fatal, auth failure, tenant suspendedNo / manual actionNo
Modal dialogConfirmation required before retrying a destructive actionYes after confirmYes
Offline indicatorNetwork unavailable; queued for retryAuto (when online)No
Skeleton + retryFetching failed on a card/panel; data still loadableYes (manual)
Silent retryretriable: true, no user action required; show spinnerAuto

2. Error-to-UI mapping

2.1 GENERAL

Error codeHTTPUI patternUser messageRetry CTAEscalationSurface(s)
MELMASTOON.GENERAL.RESOURCE_NOT_FOUND404Full-screen error or skeleton + retry depending on contexterrors.general.resource_not_found"Go home"all
MELMASTOON.GENERAL.VALIDATION_FAILED422Inline field errors (per errors[] array)errors.general.validation_failedall
MELMASTOON.GENERAL.PRECONDITION_FAILED412Toast with "Reload" CTAerrors.general.precondition_failed"Reload"all
MELMASTOON.GENERAL.CROSS_TENANT_REFERENCE422Toast (technical; phrased as "Something went wrong")errors.general.cross_tenant_referenceLog alertoperator-desktop
MELMASTOON.GENERAL.RATE_LIMITED429Toast with countdown timer; auto-retry after retryAftererrors.general.rate_limitedAutoall
MELMASTOON.GENERAL.INTERNAL500Toast "Something went wrong" + trace ID (collapsed)errors.general.internal"Try again"Sentry alertall

2.2 IDENTITY

Error codeHTTPUI patternUser messageRetry CTAEscalationSurface(s)
MELMASTOON.IDENTITY.INVALID_CREDENTIALS401Inline field error on login formerrors.identity.invalid_credentialsLock after 5 attemptsall
MELMASTOON.IDENTITY.TOKEN_EXPIRED401Silent token refresh → if fails, modal "Session expired, please log in"errors.identity.token_expiredAuto refresh → re-login modalall
MELMASTOON.IDENTITY.MFA_REQUIRED401Step-up MFA modalerrors.identity.mfa_requiredoperator-desktop, control-plane-web
MELMASTOON.IDENTITY.DEVICE_NOT_BOUND403Full-screen error with device pairing instructionserrors.identity.device_not_bound"Pair device"operator-desktop
MELMASTOON.IDENTITY.PERMISSION_DENIED403Inline banner "You do not have permission to do this"errors.identity.permission_deniedall
MELMASTOON.IDENTITY.SESSION_REVOKED401Full-screen error, force logouterrors.identity.session_revoked"Log in again"all

2.3 TENANT

Error codeHTTPUI patternUser messageRetry CTAEscalationSurface(s)
MELMASTOON.TENANT.NOT_FOUND404Full-screen error "Property not found"errors.tenant.not_foundtenant-booking-web, consumer-mobile
MELMASTOON.TENANT.SUSPENDED403Full-screen error "This property is temporarily unavailable"errors.tenant.suspendedNotify GM if in operator-desktopall
MELMASTOON.TENANT.NOT_A_MEMBER403Full-screen error "You don't have access to this property"errors.tenant.not_a_memberoperator-desktop
MELMASTOON.TENANT.PLAN_LIMIT_EXCEEDED402Modal "Plan limit reached — upgrade your plan"errors.tenant.plan_limit_exceeded"Upgrade"operator-desktop, control-plane-web
MELMASTOON.TENANT.CONFIGURATION_INVALID422Inline banner in configuration panelerrors.tenant.configuration_invalidFix fields → savecontrol-plane-web, operator-desktop

2.4 RESERVATION

Error codeHTTPUI patternUser messageRetry CTAEscalationSurface(s)
MELMASTOON.RESERVATION.OVERBOOKING_BLOCKED409Full-screen error within booking funnel "This room is no longer available — another guest just booked it"errors.reservation.overbooking_blocked"Find another room"tenant-booking-web, consumer-mobile
MELMASTOON.RESERVATION.HOLD_EXPIRED410Modal "Your hold expired — please start over" + countdown in timererrors.reservation.hold_expired"Start over"tenant-booking-web, consumer-mobile
MELMASTOON.RESERVATION.INVALID_STATE_TRANSITION409Toast "This action is not allowed at this stage"errors.reservation.invalid_state_transitionoperator-desktop
MELMASTOON.RESERVATION.GUEST_INFO_INCOMPLETE422Inline field errors on guest capture formerrors.reservation.guest_info_incompleteoperator-desktop, tenant-booking-web
MELMASTOON.RESERVATION.CHECKIN_WINDOW_VIOLATED409Inline banner "Check-in is only available between HH:MM and HH:MM; request an override?"errors.reservation.checkin_window_violated"Request override"operator-desktop
MELMASTOON.RESERVATION.CANCELLATION_NOT_ALLOWED409Modal "This booking cannot be cancelled under the non-refundable policy"errors.reservation.cancellation_not_allowedoperator-desktop, tenant-booking-web

2.5 INVENTORY

Error codeHTTPUI patternUser messageRetry CTAEscalationSurface(s)
MELMASTOON.INVENTORY.INSUFFICIENT_AVAILABILITY409Funnel error "No rooms available for these dates"errors.inventory.insufficient_availability"Change dates"tenant-booking-web, consumer-mobile
MELMASTOON.INVENTORY.STOP_SELL_ACTIVE409Inline banner on calendar "These dates are closed"errors.inventory.stop_sell_active"Change dates"tenant-booking-web, operator-desktop
MELMASTOON.INVENTORY.MIN_LOS_VIOLATED422Inline banner "Minimum stay is N nights"errors.inventory.min_los_violated"Adjust dates"tenant-booking-web, consumer-mobile
MELMASTOON.INVENTORY.MAX_LOS_VIOLATED422Inline banner "Maximum stay is N nights"errors.inventory.max_los_violated"Adjust dates"tenant-booking-web
MELMASTOON.INVENTORY.OVERSELL_DETECTED500Toast "Something went wrong — our team has been alerted"errors.general.internalP0 alert to on-calloperator-desktop

2.6 PRICING

Error codeHTTPUI patternUser messageRetry CTAEscalationSurface(s)
MELMASTOON.PRICING.RATE_PLAN_NOT_FOUND404Skeleton + retry on rate carderrors.pricing.rate_plan_not_found"Reload"tenant-booking-web
MELMASTOON.PRICING.QUOTE_EXPIRED410Modal "Prices may have changed — your quote has expired"errors.pricing.quote_expired"Re-quote"tenant-booking-web, consumer-mobile
MELMASTOON.PRICING.CURRENCY_MISMATCH422Toast "Currency mismatch — refreshing…" + auto re-quoteerrors.pricing.currency_mismatchAutotenant-booking-web
MELMASTOON.PRICING.DERIVATION_FAILED500Silent retry (retriable) → after 3 attempts, toasterrors.pricing.derivation_failedAuto → "Try again"tenant-booking-web

2.7 BILLING

Error codeHTTPUI patternUser messageRetry CTAEscalationSurface(s)
MELMASTOON.BILLING.FOLIO_LOCKED409Modal "This folio is closed — a supervisor can reopen it"errors.billing.folio_locked"Request reopen"operator-desktop
MELMASTOON.BILLING.CHARGE_INVALID422Inline field errors on charge formerrors.billing.charge_invalidoperator-desktop
MELMASTOON.BILLING.REFUND_EXCEEDS_BALANCE422Inline field error "Refund cannot exceed remaining balance of AFN X"errors.billing.refund_exceeds_balanceoperator-desktop
MELMASTOON.BILLING.RECONCILIATION_MISMATCH500Full-screen error on EOD panel + finance on-call alerterrors.general.internalP0 finance alertoperator-desktop
MELMASTOON.BILLING.TAX_RULE_MISSING422Toast "Tax rule not configured for this charge — contact your admin"errors.billing.tax_rule_missingoperator-desktop

2.8 PAYMENT

Error codeHTTPUI patternUser messageRetry CTAEscalationSurface(s)
MELMASTOON.PAYMENT.DECLINED402Inline error on payment step "Your card was declined — try a different card or pay on arrival"errors.payment.declined"Try again / Switch method"tenant-booking-web, consumer-mobile
MELMASTOON.PAYMENT.INSUFFICIENT_FUNDS402Same as DECLINED, distinct copyerrors.payment.insufficient_funds"Switch method"tenant-booking-web, consumer-mobile
MELMASTOON.PAYMENT.GATEWAY_TIMEOUT504Toast "Payment service is slow — retrying…" → auto-retry 2x → "Please try again later"errors.payment.gateway_timeoutAuto 2x → manualtenant-booking-web, consumer-mobile
MELMASTOON.PAYMENT.INTENT_NOT_FOUND404Modal "Your payment session expired — start over"errors.payment.intent_not_found"Start over"tenant-booking-web
MELMASTOON.PAYMENT.CASH_RECONCILIATION_PENDING202Not an error — informational toast "Cash payment pending reconciliation by front desk"errors.payment.cash_reconciliation_pendingoperator-desktop

2.9 LOCK

Error codeHTTPUI patternUser messageRetry CTAEscalationSurface(s)
MELMASTOON.LOCK.VENDOR_UNREACHABLE502Modal "Key system is unavailable — fall back to mechanical key?"errors.lock.vendor_unreachable"Use mechanical key"operator-desktop, kiosk
MELMASTOON.LOCK.KEY_ISSUE_FAILED502Modal with retry + mechanical key fallbackerrors.lock.key_issue_failed"Retry / Use mechanical key"operator-desktop, kiosk
MELMASTOON.LOCK.KEY_REVOKE_FAILED502Toast "Key could not be revoked — alert maintenance"errors.lock.key_revoke_failed"Retry"Security alertoperator-desktop
MELMASTOON.LOCK.CARD_ENCODER_OFFLINE503Inline banner "Card encoder offline — encode when reconnected"errors.lock.card_encoder_offlineAuto on reconnectoperator-desktop
MELMASTOON.LOCK.DEVICE_NOT_PAIRED409Inline banner with "Pair lock device" linkerrors.lock.device_not_paired"Pair device"operator-desktop
MELMASTOON.LOCK.CREDENTIAL_EXPIRED410Toast "Key expired — re-issue required"errors.lock.credential_expired"Re-issue key"operator-desktop

2.10 HOUSEKEEPING

Error codeHTTPUI patternUser messageRetry CTAEscalationSurface(s)
MELMASTOON.HOUSEKEEPING.ROOM_STATE_CONFLICT409Toast "Room status changed — refresh your view"errors.housekeeping.room_state_conflict"Refresh"operator-desktop, kiosk, staff-mobile
MELMASTOON.HOUSEKEEPING.TASK_ALREADY_COMPLETED409Toast "This task was already completed"errors.housekeeping.task_already_completedoperator-desktop, kiosk, staff-mobile
MELMASTOON.HOUSEKEEPING.STAFF_UNAVAILABLE409Inline banner on assignment panelerrors.housekeeping.staff_unavailable"Assign to another"operator-desktop

2.11 SYNC (desktop)

Error codeHTTPUI patternUser messageRetry CTAEscalationSurface(s)
MELMASTOON.SYNC.CONFLICT_UNRESOLVABLE409Modal with side-by-side conflict resolution UIerrors.sync.conflict_unresolvableManual pickoperator-desktop
MELMASTOON.SYNC.SEQUENCE_GAP409Inline banner "Sync incomplete — some events may be missing"errors.sync.sequence_gap"Force full sync"operator-desktop
MELMASTOON.SYNC.PUSH_REJECTED422Toast "A change couldn't be saved — check sync log"errors.sync.push_rejectedoperator-desktop
MELMASTOON.SYNC.STATE_CORRUPT500Full-screen error "Local data is corrupted — reset required" + backup prompterrors.sync.state_corrupt"Reset + resync"P1 Sentry alertoperator-desktop

2.12 THEME

Error codeHTTPUI patternUser messageRetry CTAEscalationSurface(s)
MELMASTOON.THEME.CONTRAST_INVARIANT_VIOLATED422Inline error on token picker "This color combination fails WCAG AA contrast"errors.theme.contrast_invariant_violatedFix tokencontrol-plane-web
MELMASTOON.THEME.RTL_VARIANT_MISSING422Inline error on token formerrors.theme.rtl_variant_missingAdd RTL variantcontrol-plane-web
MELMASTOON.THEME.PUBLISH_IN_PROGRESS409Toast "A publish is already in progress — try again shortly"errors.theme.publish_in_progressAuto poll → retrycontrol-plane-web

3. Offline error handling (desktop)

When the Electron desktop is offline:

  • Do not surface BFF error codes — the request never reached the BFF.
  • Show the Offline indicator pattern (sticky banner or status icon in nav).
  • All mutations go to the local outbox; confirm to the user via "Saved locally — will sync when reconnected".
  • Reads fall through to local SQLite; show a "data as of <last sync time>" label.
  • After reconnect, flush outbox. Surface any SYNC.* errors from the flush.

4. Error UX rules

  1. Never show raw error codes to end users; show the userMessageKey string only.
  2. Always show a trace ID (collapsed toggle) on 5xx errors so support can correlate.
  3. Never auto-dismiss errors that require user action (payment failed, folio locked, etc.).
  4. Toast auto-dismiss is 5 seconds for non-critical, 8 seconds for recoverable errors with retry.
  5. Retry limits: automatic retries cap at 3 attempts with exponential backoff (200 ms, 400 ms, 800 ms). After cap, show manual retry CTA.
  6. Accessibility: all error states must be announced via role="alert" or aria-live="assertive". Do not rely on color alone.

5. Open Questions

  • Should we add userMessageKeyShort for toast-specific shorter copy (current key strings may be too long for 1-line toasts)?
  • Should SYNC.CONFLICT_UNRESOLVABLE trigger a push notification to the GM if unresolved for > 5 minutes?
  • How should kiosk handle LOCK.KEY_ISSUE_FAILED? The kiosk has no "call front desk" affordance — add an in-kiosk staff-paging button?

References