V8 Central — Product & Technical Spec
  1. Docs
  2. Delivery
  3. Edge-case matrix

#Edge-case matrix

For each case: trigger → backend response → frontend behaviour → user message → recovery. Status codes follow the OSS conventions where Central has no API yet Assumption. Messages are i18n keys in the build (the English shown is the source text).

#CaseTriggerBackend responseFrontend behaviourUser messageRecovery
1Invalid loginWrong email/password422/401 genericClear password, focus it"Incorrect email or password."Retry / forgot password
2Unverified accountLogin before verifyingLogin succeeds — corrected 2026-10-09. The backend moved 2.2 / 2.3 to the V7 flow: an unverified user can log in and use the panel. email_verified comes back with the userA reminder banner, not a block — with Resend"Please verify your email address."Resend link
2zAn action that needs a verified emailOnly four: sending / resending an invitation, ownership transfer (4.7), creating a server (8.8), promo credits (Phase 7)403 code: email_not_verifiedRefuse just that action and point at ResendThe backend's messageGuard these four, not the app. An earlier version of this row blocked login itself, which is wrong
2aUnverified state cleared another wayAnywhere after loginThree routes out, as of 2026-10-09: the verify link (2.2), a password reset (2.5) and a social login (2.4)—Read the verified flag from the API after every login and on session restore — never infer it from how the account was created, and never cache it for the session. A banner that outlives the state it describes is the bug these routes invite—
2bProvider returns an unverified emailGoogle / GitHub loginLinking or creating requires a provider-verified email (2.4, 2026-10-09), so the sign-in stopsNo retryBelongs in the /login?error=<code> list. The message must be actionable — name the cause and the fix (the address is not verified with the provider) rather than a generic failure. Code and wording still to come from the backend Open questionProvider
3Banned / lockedLogin403 code: account_banned (corrected 2026-10-09 — was a guess, banned)No retry"This account is locked. Contact support."Support
3bIP whitelist on, and the user's address keeps changingLoginExact IP matching (2.8, 2026-10-09) means every new address is blocked afresh — a dynamic home IP or mobile connection needs a new emailed approval each time, then another loginNo retryThe blocked screen must not imply a one-off. A new approval email only once per 5 minutes per IP, so no resend button that silently does nothing. The warning belongs on the switch in Account → IP whitelist (3.10), before it is turned onAccount owner
3aBanned account tries a password resetForgot / reset passwordNo email is sent; an existing link is refused (2.5, 2026-10-09)No retryForgot form: the generic "if an account exists, we sent a link" — saying banned here would reveal account state to anyone typing an email. Reset screen: "This link can no longer be used" — not expired, because it has not timed out Open question (the backend does not state either message)Support
4Unknown IP (whitelist on)Login from a new IP403 code: ip_not_approvedApproval-sent screen"We emailed you a link to approve this IP."Click link (24 h)
52FA wrong codeBad code422, attempts leftShake + counter"That code is wrong. N tries left."Resend / backup code
6Session expiredToken expired401Refresh once, else to login"Your session expired. Please log in again."Log in → return to next
7No organizationLogin with none200 empty listRoute to create organization"Create your organization to get started."Create
8Organization deletedCurrent org gone404 on scoped callsClear current, switch to main/first"That organization is no longer available."Pick another
9Member removedMembership revoked403/404Same as 8"You no longer have access to ."Ask an owner
10Permission deniedAction without grant403 code: forbidden403 state / toast, refresh permissions"You don't have permission to do this."Ask an owner
11Plan expiredSubscription expired403 code: subscription_expired (V7 sends 500 + message)Banner, actions disabled"Your subscription has expired. Renew to continue."Renew
12Subscription cancelledCancel flag set200 status cancelled"Ends on " badge"Your plan ends on ."Resume
13Payment failedGateway declinedTransaction failedReturn page shows failure"The payment didn't go through. Nothing was charged."Retry / other method
14Payment pendingGateway slowTransaction pendingPoll, then "processing""We're confirming your payment. This can take a few minutes."Wait / email
15Not enough creditPlan change > balance422 code: insufficient_credit + amountShow top-up with the amount"Add $N to your wallet to continue."Top up
16Usage limit reachedAdd server over limit403 code: plan_limit_reachedUpgrade dialog"Your plan allows N servers."Upgrade / disconnect
17Server offlineOSS timeout504 code: server_unreachableUnreachable state"This server isn't responding (last seen …)."Retry / check server
18Invalid keyOSS 401 on connect422 code: invalid_server_keyField error"This Central key isn't valid."Copy the key again
19Key revoked laterOSS 401 on use409/424 code: server_unauthorizedReconnect banner"Central can no longer access this server."Paste the new key
20Duplicate serverAlready linked409 code: server_already_connectedField error"This server is already connected."Open the existing one
21Version mismatchOSS older than minimum422 code: oss_version_unsupportedExplain + docs link"Update the panel to vX.Y or newer."Update the panel
22Provider failureProvider API error502 code: provider_error + provider messageKeep the form" said: …"Fix / retry
23Provider token expiredOAuth expired, refresh failed401 code: provider_reauthReconnect button"Reconnect your account."OAuth again
24VPS creation failureCreate/boot/install failedJob status failed + stepProgress shows the failed step"Server creation failed at ."Retry / delete VPS
25Blueprint deployment failureAdd-on run failed / steps failedRun failed or completed: falsePer-step results"Blueprint finished with N failed steps."Retry / edit
26Add-on not installed / no licenceOSS 404/403 add-on codesPassed throughInstall/buy hint"WP Toolkit isn't installed / licensed on this server."Install / buy
27API timeoutCentral slowClient timeoutError state + retry"This is taking too long."Retry
28Network errorOfflineNo responseOffline banner, keep form data"You appear to be offline."Retry when online
29404Wrong URL / other org's resource404not-found page"This page doesn't exist."Back / dashboard
30500Bug500 + referenceError state + reference"Something went wrong. Reference: …"Retry / support
31429Too many requests429 + Retry-AfterDisable action, countdownShow the backend's own sentence — "Too many attempts. Please try again in N seconds." (published 2026-10-09, already translated, and it carries the number)Wait
31a429 on a sensitive formPassword change, delete account (5 / min), email-change request (3 / 10 min)429 + Retry-AfterButton disabled with the seconds counting down; the form keeps what was typedThe backend's messageThese limits are far tighter than ordinary reads (60 / min), so a user who mistypes their current password a few times will hit one. Never clear the form on a 429
31kYour default organization was deleted by its ownerA member whose default was someone else's organizationTheir default moves on its own (backend, 4.2)On the next load the switcher shows a different organizationTell them, once: " was deleted. You are now in ."The user changed nothing and their context moved — silently switching them is how people end up acting in the wrong organization
31lAn Admin opens Delete organizationAdmin, not owner403Hide or disable the action for Admins—Do not let it fail on click — the backend is owner-only
31hIP whitelist turned offThe switch goes off200 — "All whitelisted IPs were removed."Confirm first: the list is deleted, not pausedOur own confirmationTurning it back on does not restore anything — the user would have to add every address again
31iRemoved the IP you are usingDeleting your own row from the whitelist200 with removed_current_ip: trueWarn, but allow it"This session keeps working, but your next login from this address will need an emailed approval."Do not block it — the backend allows it and tells us it happened
31j100 IPs reachedAdding the 101st address422Disable Add, show the countThe backend's "You can whitelist at most 100 IP addresses."Show how many are used before they hit it
31eAuthenticator setup ran out of timeThe QR sat on screen longer than 10 minutes before the code was entered422 on confirm, with its own messageClose the step and offer Start againThe backend's "The setup has expired…"Fail cleanly — a fresh QR is one click away, so never leave a dead QR on screen
31fLast backup code usedavailable reaches 0 (or 1) in the 2FA status—Warn on the Security tab and offer Create new codesOur own lineNothing breaks yet, which is why it needs saying early — a user with no codes left and a lost phone is locked out, and the codes cannot be read back
31gTurning 2FA off while the authenticator is onOff is one action for both200 — method becomes nullConfirm first: it also removes the authenticator and every backup codeOur own confirmationSay what else goes — the user is likely thinking only of the email codes
31cSession already goneLogging out a device that signed out by itself, or whose token expired404Refresh the list; treat it as done"That device is already signed out."Not an error — the device is gone either way, which is what the user wanted
31dSession from before the feature existedSessions started before 2026-10-09Browser / platform Unknown, IP / method / sign-in time nullBlank cells; the row still logs out normally—Design for missing values rather than printing "Unknown" four times across one row
31bEmail-change link opened elsewhereThe confirm link is opened on a different device, or after signing outNo session at all/confirm-email-change works signed out, then points to loginThe backend's result messageBy design — the backend's confirm call takes no token. The page must not redirect a signed-out visitor to login before confirming
32Concurrent editTwo admins edit a role409 or last-write-wins Open questionReload prompt"This was changed by someone else."Reload
33Owner removes self / last ownerRemove member422Refuse"An organization needs an owner."Transfer ownership Open question
34Delete org with serversDelete422 (V7: 500 + message)Link to servers"Disconnect all servers first."Disconnect
35Delete protection onAny delete, anywhere423 (corrected 2026-10-09 — was a guessed 403; 2026-10-27 Pair 2: now on all 8 Application-panel delete actions too, not on unban): every delete route carries a delete.protection check and answers 423 "turn off delete protection first". V7 only checked this in the frontend, so in V8 this can arrive even where no guard was builtExplain the setting and link to it"Delete protection is on."Turn it off in Security
36Invitation expired / usedOpen the link410/404Invite-invalid page"This invitation is no longer valid."Ask for a new invite
37Locale missingKey not translated—English fallback(English text)Translate