<!-- Source: https://developers.memberstack.com/dom-package/error-handling -->
<!-- Markdown version of a Memberstack developer documentation page. Canonical HTML: https://developers.memberstack.com/dom-package/error-handling -->

# 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.

```javascript
// 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
}
```

> 💡 **Tip:**
>
> The `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.

```javascript
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.

```javascript
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.

```javascript
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.

```javascript
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.

```javascript
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.

```javascript
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.).

```javascript
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.

```javascript
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.

```javascript
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.

```javascript
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

```jsx
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

```svelte
<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}
```
