Error Handling
Memberstack provides a rich error handling system with structured error objects, utility functions for extracting error information, and a complete set of error codes for programmatic handling. Every error includes actionable suggestions to help you resolve issues quickly.
Quick Overview
All error utilities are exported directly from @memberstack/dom. Import them alongside any other methods you use.
Error Object Structure
When a Memberstack method fails, the thrown error contains structured information to help you handle it programmatically and display helpful messages to users.
// Every Memberstack error includes these fields:
{
message: "The provided credentials are invalid.", // Human-readable message
code: "invalid-credentials", // Machine-readable error code
statusCode: 401, // HTTP status code
category: "authentication", // Error category for grouping
suggestions: [ // Actionable fix suggestions
"Verify the email address is spelled correctly",
"Check if Caps Lock is enabled"
],
docsUrl: "https://docs.memberstack.com/..." // Link to relevant docs
}suggestions array is especially useful for building user-facing error messages. Each suggestion is a plain-English action the user can take to resolve the issue.Utility Functions
Memberstack exports helper functions for safely extracting information from error objects. These are safer than accessing properties directly because they handle cases where the error may not be a Memberstack error.
import {
isErrorCode,
getErrorMessage,
getErrorCode,
getErrorCategory,
getErrorSuggestions,
getErrorDocsUrl,
formatErrorForUser,
getErrorReport,
isMemberstackError,
ErrorCodes
} from '@memberstack/dom';getErrorMessage(error)
Extracts the human-readable error message from any error object.
try {
await memberstack.loginMemberEmailPassword({ email, password });
} catch (error) {
const message = getErrorMessage(error);
// "The provided credentials are invalid."
// Display to user
document.getElementById('error').textContent = message;
}isErrorCode(error, code)
Checks if an error matches a specific error code. Use this with the ErrorCodes constant for type-safe error checking.
import { isErrorCode, ErrorCodes } from '@memberstack/dom';
try {
await memberstack.signupMemberEmailPassword({ email, password });
} catch (error) {
if (isErrorCode(error, ErrorCodes.EMAIL_ALREADY_EXISTS)) {
// Suggest logging in instead
showMessage("This email is already registered. Try logging in.");
} else if (isErrorCode(error, ErrorCodes.INVALID_PASSWORD)) {
showMessage("Password doesn't meet the requirements.");
} else if (isErrorCode(error, ErrorCodes.INVALID_EMAIL)) {
showMessage("Please enter a valid email address.");
} else {
showMessage(getErrorMessage(error));
}
}getErrorCategory(error)
Returns the error category, useful for grouping errors in your UI or logging.
const category = getErrorCategory(error);
switch (category) {
case 'authentication':
// Show login-related error UI
break;
case 'validation':
// Highlight invalid form fields
break;
case 'payment':
// Show payment-related error UI
break;
case 'authorization':
// Show access denied message
break;
case 'not_found':
// Show "not found" message
break;
case 'network':
// Show "check your connection" message
break;
}
// Available categories:
// 'authentication' | 'authorization' | 'validation' | 'not_found'
// 'conflict' | 'payment' | 'limit' | 'account'
// 'data_tables' | 'network' | 'unknown'getErrorSuggestions(error)
Returns an array of actionable suggestions for resolving the error. These are plain-English strings suitable for displaying to end users.
const suggestions = getErrorSuggestions(error);
// ["Verify the email address is spelled correctly", "Check if Caps Lock is enabled"]
if (suggestions?.length) {
suggestions.forEach(suggestion => {
const li = document.createElement('li');
li.textContent = suggestion;
errorList.appendChild(li);
});
}formatErrorForUser(error)
Returns a concise, user-friendly message for the error — a curated message keyed off the error code (it does not append the suggestions list). This is the quickest way to show a helpful error to your users; pair it with getErrorSuggestions() if you also want to render actionable steps.
try {
await memberstack.loginMemberEmailPassword({ email, password });
} catch (error) {
const userMessage = formatErrorForUser(error);
alert(userMessage);
// Example output (a single curated sentence):
// "Invalid email or password. Please check your credentials and try again."
}isMemberstackError(error)
Type guard that checks if an error is a Memberstack error (as opposed to a network error, TypeError, etc.).
try {
await memberstack.signupMemberEmailPassword({ email, password });
} catch (error) {
if (isMemberstackError(error)) {
// Safe to access .code, .category, .suggestions, etc.
console.log('Memberstack error:', error.code, error.category);
} else {
// Network error, TypeError, or other non-Memberstack error
console.error('Unexpected error:', error);
}
}getErrorReport(error)
Returns a detailed error report object with all available information. Useful for logging and debugging.
const report = getErrorReport(error);
// {
// message: "The provided credentials are invalid.",
// code: "invalid-credentials",
// statusCode: 401,
// category: "authentication",
// suggestions: ["Verify the email...", "Check if Caps Lock..."],
// docsUrl: "https://docs.memberstack.com/..."
// }
// Log to your error tracking service
errorTracker.captureError(report);Error Codes Reference
Use the ErrorCodes constant for type-safe error code checking. All codes are accessible as properties on the ErrorCodes object.
import { ErrorCodes, isErrorCode } from '@memberstack/dom';
// Use with isErrorCode() for type-safe checking
if (isErrorCode(error, ErrorCodes.INVALID_CREDENTIALS)) {
// handle invalid credentials
}Authentication Errors
| ErrorCodes Constant | Code Value | Description |
|---|---|---|
INVALID_CREDENTIALS | invalid-credentials | Wrong email or password |
INVALID_TOKEN | client/invalid-token | Invalid or expired auth token |
MEMBER_NOT_FOUND | member-not-found | No member found with this email |
INVALID_RESET_CODE | invalid-reset-code | Invalid or expired password reset code |
INVALID_PASSWORDLESS_CODE | invalid-passwordless-login-code | Invalid or expired passwordless code |
LOGIN_REQUIRED | login-required | Member must be logged in |
Account & Social Login Errors
| ErrorCodes Constant | Code Value | Description |
|---|---|---|
EMAIL_ALREADY_EXISTS | email-already-in-use | Email is already registered |
USE_SOCIAL_LOGIN | use-social-login | Account registered via social provider |
USE_EMAIL_LOGIN | use-email-login | Account registered with email/password |
NO_PASSWORD_SET | no-password-set | Member doesn't have a password set |
ACCOUNT_ALREADY_CONNECTED | account-already-connected | Provider already connected to this account |
ACCOUNT_NOT_CONNECTED | account-not-connected | Provider not connected to this account |
ACCOUNT_CONNECT_FAILED | account-connect-failed | Failed to connect provider |
ACCOUNT_CONNECT_REQUIRES_LOGIN | account-connect-requires-login | Must be logged in to connect a provider |
ACCOUNT_SET_PASSWORD_FIRST | account-set-password-before-disconnect | Set a password before disconnecting the only provider |
ACCOUNT_NOT_FOUND | account-not-found | No account found for this provider |
Validation Errors
| ErrorCodes Constant | Code Value | Description |
|---|---|---|
INVALID_EMAIL | invalid-email | Invalid email format |
INVALID_PASSWORD | invalid-password | Password doesn't meet requirements |
PASSWORD_TOO_SHORT | invalid-password-too-short | Password is too short (min 8 characters) |
REQUIRED_FIELD_MISSING | required-field-missing | A required field was not provided |
INVALID_CAPTCHA | invalid-captcha | Captcha verification failed |
Plan & Subscription Errors
| ErrorCodes Constant | Code Value | Description |
|---|---|---|
PLAN_NOT_FOUND | plan-not-found | Plan ID doesn't exist |
NO_PLAN_FOUND | no-plan-found | No plan found for this member |
ALREADY_HAS_PLAN | already-have-plan | Member already has this plan |
PLAN_NOT_FREE | plan-not-free | Cannot add a paid plan with addPlan() |
PLAN_MEMBER_LIMIT_REACHED | plan-member-limit-reached | Plan has reached its member limit |
PLAN_RESTRICTED_TO_ADMIN | plan-restricted-to-admin | Plan can only be assigned by admin |
DOMAIN_NOT_PERMITTED | domain-not-permitted | Email domain not allowed for this plan |
PRICE_NOT_AVAILABLE | price-no-longer-available | Price is no longer available |
Data Table Errors
| ErrorCodes Constant | Code Value | Description |
|---|---|---|
DATA_TABLE_NOT_FOUND | data-table-not-found | Table key doesn't exist |
DATA_RECORD_NOT_FOUND | data-record-not-found | Record ID doesn't exist |
INVALID_TABLE_KEY | invalid-table-key | Invalid table key format |
UNIQUE_CONSTRAINT_VIOLATION | unique-constraint-violation | Duplicate value in unique field |
FIELD_LIMIT_EXCEEDED | field-limit-exceeded | Too many fields in table |
INVALID_FIELD_TYPE | invalid-field-type | Wrong data type for field |
INVALID_FIELD_VALUE | invalid-field-value | Invalid value for field |
Other Errors
| ErrorCodes Constant | Code Value | Description |
|---|---|---|
ACCESS_DENIED | access-denied | Insufficient permissions |
INVALID_FILE_TYPE | invalid-file-type | Unsupported file type for upload |
FILE_TOO_LARGE | file-size-too-large | File exceeds size limit |
APP_NOT_FOUND | app-not-found | Application not found for this key |
TEST_MODE_LIMIT_REACHED | test-mode-member-limit-reached | Sandbox member limit reached |
NETWORK_ERROR | network-error | Network connection issue |
UNKNOWN_ERROR | unknown-error | An unexpected error occurred |
Complete Example
Here's a full example showing how to use the error handling utilities together in a signup form.
import memberstack from '@memberstack/dom';
import {
isErrorCode,
ErrorCodes,
getErrorMessage,
getErrorCategory,
getErrorSuggestions,
formatErrorForUser,
isMemberstackError
} from '@memberstack/dom';
async function handleSignup(email, password) {
try {
const result = await memberstack.signupMemberEmailPassword({
email,
password
});
// Success - redirect or update UI
window.location.href = result.data.redirect || '/dashboard';
} catch (error) {
// Check for specific error codes
if (isErrorCode(error, ErrorCodes.EMAIL_ALREADY_EXISTS)) {
showError('This email is already registered. Would you like to log in instead?');
showLoginLink();
return;
}
if (isErrorCode(error, ErrorCodes.PASSWORD_TOO_SHORT)) {
showError('Password must be at least 8 characters.');
highlightField('password');
return;
}
if (isErrorCode(error, ErrorCodes.INVALID_EMAIL)) {
showError('Please enter a valid email address.');
highlightField('email');
return;
}
if (isErrorCode(error, ErrorCodes.TEST_MODE_LIMIT_REACHED)) {
showError('Test mode member limit reached. Delete some test members or switch to live mode.');
return;
}
// For any other error, show the formatted message with suggestions
if (isMemberstackError(error)) {
showError(formatErrorForUser(error));
} else {
// Non-Memberstack error (network issue, etc.)
showError('Something went wrong. Please check your connection and try again.');
console.error('Unexpected error:', error);
}
}
}Framework Examples
React
import { useState } from 'react';
import { isErrorCode, ErrorCodes, getErrorMessage, getErrorSuggestions } from '@memberstack/dom';
function LoginForm({ memberstack }) {
const [error, setError] = useState(null);
const [suggestions, setSuggestions] = useState([]);
async function handleLogin(e) {
e.preventDefault();
setError(null);
setSuggestions([]);
const formData = new FormData(e.target);
try {
await memberstack.loginMemberEmailPassword({
email: formData.get('email'),
password: formData.get('password')
});
} catch (err) {
setError(getErrorMessage(err));
setSuggestions(getErrorSuggestions(err) || []);
}
}
return (
<form onSubmit={handleLogin}>
<input name="email" type="email" placeholder="Email" />
<input name="password" type="password" placeholder="Password" />
<button type="submit">Log In</button>
{error && (
<div className="error">
<p>{error}</p>
{suggestions.length > 0 && (
<ul>
{suggestions.map((s, i) => <li key={i}>{s}</li>)}
</ul>
)}
</div>
)}
</form>
);
}Svelte 5
<script>
import { getErrorMessage, getErrorSuggestions, isErrorCode, ErrorCodes } from '@memberstack/dom';
import { getMemberstack } from '$lib/memberstack';
let error = $state(null);
let suggestions = $state([]);
async function handleLogin(email, password) {
error = null;
suggestions = [];
const ms = getMemberstack();
try {
await ms.loginMemberEmailPassword({ email, password });
} catch (err) {
error = getErrorMessage(err);
suggestions = getErrorSuggestions(err) || [];
}
}
</script>
{#if error}
<div class="error">
<p>{error}</p>
{#if suggestions.length > 0}
<ul>
{#each suggestions as suggestion}
<li>{suggestion}</li>
{/each}
</ul>
{/if}
</div>
{/if}