Handling errors in Vue
Handle Qubeforms API errors in Vue forms while preserving visitor input. Manage validation feedback, rate limits, network loss, navigation, and duplicate submissions.
1. Keep form and request state separate
Use ref for pending and feedback state and reactive or individual refs for entered values. The basic Vue component blocks concurrent submits and snapshots FormData before disabling fields. Browser validation handles common missing or malformed inputs, while server errors still need their own visible message.
2. Parse responses defensively
Keep existing field values after an error and clear them only after response.ok and result.ok === true. Use error.message for server feedback and render it as text, not HTML. The API does not promise a per-field error map, so do not assume error.details always contains field names. A proxy may return HTML or an empty body; guard JSON parsing and retain a fallback message. A network exception does not prove that the submission failed to arrive.
const result = await response.json().catch(() => null);
if (!response.ok || result?.ok !== true) {
feedback.value = result?.error?.message || `Could not confirm receipt (HTTP ${response.status}).`;
return;
}
// Reset reactive values only after confirmed success.3. Use status-specific guidance
Read both HTTP status and error.message. For XHR use xhr.status and guarded parsing of xhr.responseText. These are API errors rather than Vue template errors. A 422 redirect error can occur after storage; check the inbox before repeating it.
402 The plan does not allow this feature, such as file uploads.
403 Origin or access restriction.
404 Form or requested resource unavailable.
413 Request or payload too large.
422 Validation, CAPTCHA, attachment, or redirect error; inspect error.message.
429 Rate, storage, or usage limit; follow Retry-After when present.
500 Server error; receipt may be uncertain.
503 Service or storage unavailable.4. Respect rate limits and duplicate protection
Read the Retry-After delay in seconds on 429 and show it to the visitor. The basic Vue examples display the delay but do not enforce a countdown. Do not automatically resend from a watcher, on remount, or in a tight loop. If you implement retries with Idempotency-Key, retain one key for the unchanged logical submission; changing values requires a new key. Reusing a key returns the existing record without comparing a new payload, and each HTTP attempt still consumes rate-limit capacity.
5. Handle network loss and navigation
Keep entered values after failure and reset them only on confirmed success. If a request is aborted or times out, do not assume the server discarded it. A route change can unmount the component; the upload-progress example aborts its request locally but cannot undo server-side work. Avoid rendering messages with v-html; {{ feedback }} displays untrusted error text without treating it as markup.
6. Test before deploying
Test malformed input, invalid origin, expired CAPTCHA, large attachments, non-JSON errors, and offline mode. Verify that the loading state always ends and that fields remain available. A successful response may describe a Spam record and does not promise email delivery; inspect the returned status and delivery records when troubleshooting.
Public form keys can appear in browser code. Read keys, management credentials, and webhook signing secrets must stay on the server.