Error handling and UX explanations
1) Why it matters
An error is not a "red text," but a continuation of the script. Good UX errors:- explains what happened and what to do next,
- saves the entered data and prevents loss of progress,
- gives a safe repeat or alternative path,
- remains available (SR/keyboard) and does not reveal too much.
2) Error typology (for interface)
1. Data validation (4xx client): empty/invalid fields, format, length, rule conflict.
2. Business rules: limits, geo-constraints, KYC/KYB, duplicates, unavailable slots.
3. Rights/permissions: role, access to the resource, age restrictions.
4. Network/server: timeout, offline, 5xx, overload, rate limit.
5. Conflicts/status: 409/412 (data changed), races, locks.
6. No resource: 404/410, deleted/transferred.
7. Payment and risk: rejection by the bank/PSP, anti-fraud, limits of responsible play.
3) Channels and display level
We select the "volume" for the context:Rule: Do not hide critical in toast/hover. Where the user is watching, there is a message.
4) Copywriting errors
Structure: cause → effect → action.
Tone: honest, neutral, guilt-free.
Specifics: specify a field/condition, avoid codes and stacks.
Button-action: "Repeat," "Change card," "Reset filters," "Open chat."
Sensitive data: do not show (PAN masking, personal attributes).
Examples
Good: "Payment failed: the bank declined the transaction. Try another method or try again later.
Bad: "Error 500. Something went wrong".
Good: "The daily spending limit has been reached. Set a new limit or try tomorrow."
Good: "The file is too large (max. 25 MB). Please compress or download some files.
5) Behavior and focus (A11y)
The error is displayed in the focus context: we transfer the focus to the first erroneous field.
Living regions: 'role = "status"' (polite) for info, 'role = "alert"' (assertive) for critical.
Visible ': focus-visible', contrast ≥ AA, alternatives to color (icon/text).
We bind the message to the field via 'aria-descripedby'.
html
<label for = "pwd "> Password </label>
<input id="pwd" name="password" aria-describedby="pwd-err" aria-invalid="true">
<p id = "pwd-err" role = "alert"> Minimum 8 characters </p>
6) Retrai, backoff and idempotency
Repetition is offered if there is a chance of success (network failures, 5xx, rate limit).
Exponential backoff 1-2-4-8 s, limit of attempts, understandable button "Repeat."
Critical transactions (rates/payments): mandatory Idempotency-Key → exclude duplicates.
Rolling back optimistic updates - clear visual return + clarification.
js async function retry(fn, attempts=3){
let wait=1000; for(let i=0; i<attempts; i++){
try{ return await fn(); }catch(e){ if(i===attempts-1) throw e; await new Promise(r=>setTimeout(r,wait)); wait=2; }
}
}
7) Offline, timeouts and partial content
Offline: we show the "No connection" banner, access to the cache (read-only), synchronization queue.
Timeouts: UI timeout (3-5 seconds) → status "Waiting for confirmation..." with safe redo/undo.
Partial success: we keep what we managed; marking "not synchronized."
8) Conflicts and competitiveness
409/412: data out of date. Suggest "Update" and show the diff (which has changed).
Locks: we inform who holds the block, and how long, the "Request access" button.
9) Sample UI templates
Page Banner:html
<div class="banner banner--error" role="alert">
<strong> Connection failed. </strong> Shows cached data.
<button class =" btn btn--ghost" id = "retry "> Retry </button>
</div>
Critical error modal:
html
<div role="alertdialog" aria-labelledby="err-title" aria-describedby="err-desc">
<h2 id = "err-title "> Session expired </h2>
<p id = "err-desc "> Sign in again to continue. </p>
<button class = "btn "> Sign in </button>
<button class =" btn btn--ghost"> Home </button>
</div>
React ErrorBoundary (with correlation ID):
tsx function Fallback({ id, onRetry }: { id: string; onRetry: ()=>void }) {
return (
<div role="alert" className="banner banner--error">
<strong> We couldn't load the page. </strong>
<div> Try again. Код: <code>{id}</code> <button onClick={()=>navigator. clipboard. writeText (id)}> Copy </button> </div>
<button onClick = {onRetry}> Retry </button>
</div>
);
}
10) Error tokens (design system)
json
{
"error": {
"tones": { "danger": "#", "warning": "#", "info": "#" },
"aria": { "polite": true, "assertive": true },
"timing": { "toastMs": 3500, "retryBackoffMs": [1000,2000,4000] },
"layout": { "fieldGap": 8, "bannerIcon": 20 }
}
}
CSS presets:
css
.banner--error { background: var(--bg-danger); color: var(--on-danger); padding: 12px 16px; border-radius: 12px; }
.field-error { color: var(--role-danger); margin-top: 6px; font-size:.875rem; }
11) Security and privacy
We do not display stack traces, internal IDs, database paths.
We mask sensitive values (maps, documents).
Messages should not prompt an attacker (for example, that an account exists).
For support - correlation ID instead of parts.
json
{"level":"error","event":"payment_fail","correlation_id":"c-8f1...","user_id":"u-","route":"/pay","psp_code":"DO_NOT_EXPOSE_TO_USER"}
12) Metrics and Control
INP and the share of Long Tasks at the time of the error (the error should not "hang" the UI).
Retry success rate, errors per 1000 actions, time to restore.
CTR on "Help/Chat," percentage of forms dropped.
Heat maps: where field-errors occur most often.
13) QA checklist
Availability
- Focus on first invalid field; 'aria-describedby '/' aria-invalid' set.
- Critical messages - 'role = "alert"'; contrast ≥ AA.
Behavior
- Form data is not lost on error.
- There is a clear'Retry 'and a correct backoff.
- Offline mode/cache working; banner see.
Copywriting
- Reason → Action; without technical jargon and accusations.
- Texts are localized and do not break the grid.
Security
- No PII leak/secrets; show only secure codes/ID.
- Idempotency is enabled for critical operations.
14) The specifics of iGaming
Rate:- UI immediately records' busy '; at delay> 3 s - "Waiting for confirmation...."
- At fail: honest status ("market closed," "coefficient has changed") + safe 'Retry'.
- Idempotent key to eliminate double bid.
- We distinguish between "bank failure/PSP" vs "server failure." For the first - "Choose another method," for the second - 'Retry'.
- Transparent KYC/AML steps; links "Why is it necessary? ».
- The tone is caring, no pressure. "Limit reached - pause or update the limit."
- No outbreaks/neon; AAA contrast, availability at SR.
- Clearly explain the restrictions and suggest "Read the rules/support."
15) Anti-patterns
"Something went wrong" without action and context.
Resets the form after an error.
Hide critical in toast for 3 seconds.
Only color without text/icon.
Endless retreats without the possibility of cancellation.
Show internal codes/stack trails.
16) Documentation in the design system
Компоненты: `FieldError`, `FormError`, `PageBanner`, `AlertDialog`, `ErrorBoundary`.
Tone/contrast/timing tokens, a11y presets, and ARIA examples.
Map of typical scenarios (validation, network, rights, payments) with text templates.
"Do/Don't": real before/after screens with failure/success metrics.
Brief Summary
Make mistakes understandable and manageable: speak human language, save entered data, offer safe repetition and alternatives, respect accessibility and privacy. Then even emergency situations retain confidence and do not interrupt the user's path - especially in critical scenarios of bets and payments.