Writing Effective Error Messages
When something goes wrong, your error message can be the only thing standing between a user resolving the issue and abandoning your product. A key question to ask about every error message: does it lead users to a dead end?
For example, if someone sees "Invalid or unsupported error," do they understand what caused the problem and what to do next? Or are they stuck?
Effective error messages do two things well:
- Explain clearly and simply what happened.
- Guide users on how to fix the problem or who to contact for help.
Poor error messages cause confusion, erode trust, and overwhelm your support team. Well-crafted error messages build trust, reduce support costs, and keep users productive — even when things go wrong.
The four pillars of effective error messages
1. Clarity: explain what happened
Users can't fix problems they don't understand. Avoid jargon and tell them clearly what went wrong.
Framework: [Action] failed because [specific reason]
✓ Clear and specific
Unable to save "Q4.xlsx"
The file name contains invalid characters. File names can't include: / \ : * ? " < > |
✗ Vague and unhelpful
Invalid file name
The improved version tells users exactly which file failed, why it failed, and what characters caused the problem.
2. Context: give users the details that matter
Include specific information that helps users understand what happened in their situation.
✓ Helpful context
Can't upload "presentation.pptx"
File size: 47 MB
Maximum allowed: 25 MB
Compress the file or upgrade to a Pro account for 100 MB uploads.
✗ Missing context
File too large
Showing the actual size versus the limit helps users make decisions. The upgrade path also turns a frustration into an actionable next step.
3. Actionability: tell users what to do next
Every error message needs clear next steps. Never leave users without a path forward.
Framework: [Problem statement]. [Specific action to resolve]
✓ Clear path forward
Connection timeout
We couldn't reach the server at api.example.com.
- Check your internet connection
- Try again in a few moments
- If this keeps happening, contact support with error code: NET_408
✗ Dead end
Network error occurred
The improved version gives users a troubleshooting path and an error code for when they contact support.
4. Empathy: write like a human
Error messages should sound helpful, not robotic. Avoid accusatory language — users rarely cause errors intentionally.
✓ Helpful and neutral
We couldn't process your payment
Your card ending in 4242 was declined by your bank.
Check your card details or try a different payment method.
✗ Accusatory
Payment failed. You entered incorrect card information.
A card decline might result from low funds, fraud protection, or a bank hold — not necessarily incorrect input. The improved version avoids assumptions and treats users with respect.
Message structure template
Use this structure for most error messages:
[SEVERITY INDICATOR - if critical]
[Clear problem statement]
[Why it happened - if useful]
[Current state/impact - if relevant]
[Primary action to take]
[Alternative actions - if available]
[Support contact - if needed]Example:
⚠️ Can't publish your changes
Your draft has 3 broken links that need fixing before you can publish:
- Page 4: Link to "pricing" page not found
- Page 7: External link to expired domain
- Page 12: Anchor link "#contact" doesn't exist
Fix these links, then try publishing again. Need help? Check the troubleshooting guide.
Error severity levels
Match your message's tone and urgency to the severity of the error.
Critical errors
Impact: Nothing works, or data might be lost
Tone: Direct and urgent
Must include: Immediate action or contact information
⛔ Service unavailable
Our servers are down for emergency maintenance.
Your work is saved. Estimated recovery time: 3 PM EST.Check status: status.example.com Urgent issue? Call support at 1-800-HELP
High-priority errors
Impact: Blocks key tasks
Tone: Clear and solution-focused
Must include: Specific steps to resolve the issue
Can't generate report: missing required data
Your Sales database hasn't synced since October 10. Reports require data from the last 7 days.
- Ask your database admin to run a manual sync.
- Schedule your report after tonight's automatic sync (11 PM).
Medium-priority errors
Impact: Inconvenient, but work can continue
Tone: Informative and supportive
Must include: A workaround or retry option
Preview failed to load
We couldn't generate a preview of "document.pdf," but your file uploaded successfully.
You can still share, download, or edit the file. Try refreshing to load the preview.
Low-priority errors
Impact: Minor disruption
Tone: Brief and light
Must include: Acknowledgment of the issue
Some features unavailable offline
You can keep working, but changes won't sync until you're back online.
Real-world examples: before and after
The following examples show error message rewrites for a SaaS data encryption application.
Example 1: Authentication error
| Original | Improved | What changed and why |
|---|---|---|
| Error logging in. System cannot connect at this time. | We're unable to sign you in Your account has been deactivated. To reactivate your account, contact your administrator at admin@company.com or call ext. 5500. | The original blamed a connection issue when the real problem was account deactivation. The improved version identifies the cause, names who can help, and provides two contact options. |
Example 2: Permission denied
| Original | Improved | What changed and why |
|---|---|---|
| Access denied to this resource. Try again with an appropriate account. | You don't have permission to view "Budget_2025.xlsx" This file is restricted to Finance team members. [Request Access] [View My Files] | The original gave no useful information. The improved version names the specific file, explains the restriction, and gives two clear options. |
Example 3: Invalid input format
| Original | Improved | What changed and why |
|---|---|---|
| Invalid/Unsupported file type. Try again. | Unsupported file format for directory sync You entered: *.exe Allowed formats: • . (all file types) • *.{extension} (specific types)Examples: *.pdf, *.docx, *.xlsx | The original identified no specific problem. The improved version shows what was entered, explains the correct format, and provides examples. |
Example 4: Database connection error
| Original | Improved | What changed and why |
|---|---|---|
| ERR_DB_CONN_REFUSED: Exception at line 142 | Can't load customer data We're unable to connect to the customer database. Your recent work is saved locally. This issue usually resolves in a few minutes. Try refreshing the page. Still unavailable after 10 minutes? Contact IT support with error code: DB_503 | The original exposed a raw technical error. The improved version explains the impact, reassures users their work is saved, suggests a fix, and includes a support code. |
Technical implementation best practices
Keep user messages and logs separate
Never expose technical stack traces to users. Log all technical details separately for debugging.
// Avoid this pattern
catch (error) {
showError(error.message); // May expose technical details
}
// Use this pattern instead
catch (error) {
// Log technical details for debugging
logger.error('Document save failed', {
error: error.stack,
userId: currentUser.id,
documentId: doc.id,
timestamp: Date.now()
});
// Show a clear message to users
showError({
title: 'Unable to save document',
message: 'Try again. If this keeps happening, contact support with code: DOC_500',
code: 'DOC_500',
actions: ['retry', 'contact_support']
});
}Use progressive disclosure for details
Show essential information first. Let users expand technical details if needed.
<ErrorMessage>
<Title>Payment processing failed</Title>
<Message>
We couldn't process your payment. Verify your payment
information and try again.
</Message>
<ExpandableDetails>
<Summary>Technical details</Summary>
<Details>
Transaction ID: txn_1234567890<br />
Error code: CARD_DECLINED<br />
Provider response: Insufficient funds<br />
Timestamp: 2025-10-16 14:23:45 UTC
</Details>
</ExpandableDetails>
<Actions>
<Button primary>Update Payment Method</Button>
<Button secondary>Contact Support</Button>
</Actions>
</ErrorMessage>Security considerations
Some situations require intentionally vague messages to protect security.
Authentication errors
DO: keep it ambiguous
Incorrect username or password
Try again, or select "Forgot password" to reset your password.
DON'T: identify which part failed
Username not found
✗ Password incorrect for user@example.com
Specific messages help attackers identify valid usernames — a common first step in account compromise.
Password creation errors
During password creation, be specific:
✓ Password must contain:
✗ At least 8 characters (current: 6)
✓ One uppercase letter
✗ One number
✓ One special character (!@#$%^&*)During sign-in, keep it vague:
✓ Password doesn't meet security requirements.
Forgot your password? Select "Reset password" below.Real-time feedback during password creation helps users succeed. At sign-in, specific feedback about password rules can help attackers exploit your system.
System information disclosure
Never expose internal system details to users.
DO: use a friendly fallback
Unable to load account information
We're having technical difficulties. Try again in a few moments. If this continues, contact support.
Error code: DB_500
DON'T: expose your infrastructure
MySQL error: Table 'prod_users.accounts' doesn't exist
Can't connect to internal server prod-db-01.internal.company.com
Stack trace: at DatabaseController.fetchUser (/var/www/app/controllers/db.js
)Database names, server addresses, and stack traces give attackers a roadmap to exploit your system. Keep technical details in your logs, not your UI.
Common mistakes to avoid
1. Using technical jargon
Correct
Can't load your profile. Refresh the page or try again later.
Unable to connect to the server. Check your internet connection and try again.
Something went wrong. Try again. If this keeps happening, contact support.
Incorrect
NullReferenceException in UserController
HTTP 500 Internal Server Error
Segmentation fault (core dumped)
Technical terms alienate users. Write for the least technical person who might encounter the error.
2. Blaming the user
Correct
Enter a valid email address (example@domain.com)
Incorrect username or password. Try again or reset your password.
Add a subject line to send your message
Incorrect
You entered invalid data
Your password is wrong
You must include a subject line
Accusatory messages make users defensive. Take responsibility for the experience and offer a clear path forward.
3. Unhelpful confirmations
Correct
Delete "Project_Final.doc"? This can't be undone. [Cancel] [Delete]
Can't save changes. [Try Again] [Save Copy] [Cancel]
Connection lost. Reconnecting... [Manual Retry] [Work Offline]
Incorrect
Are you sure? Yes/No
Operation failed. OK
Error occurred. Dismiss
Vague confirmations leave users without a path forward. Clear labels and specific actions reduce confusion and support requests.
4. Confusing success with failure
Correct
Changes saved successfully
Import complete: 1,247 records added
System check passed: All services running normally
Incorrect
Error: Operation completed successfully
Failed to succeed
Warning: No problems found
Users need to recognize immediately whether something succeeded or failed. Mixing success and failure cues leads to confusion and mistakes.
Testing your error messages
1. Comprehension
Test your messages with people who didn't write them. Ask:
- "What happened here?"
- "What would you do next?"
- "Do you have enough information to fix this?"
If they're confused or guessing, the message needs revision.
2. Context
Test your errors in realistic situations. Verify:
- Does it appear at the right moment?
- Does it block information users need?
- Can users dismiss it when appropriate?
- Does it break the page layout?
- Does it work on mobile and tablet?
- Is all text visible, or does it get cut off?
- Does it stay visible until the problem is resolved?
- Do multiple simultaneous errors display cleanly?
An error that looks fine in isolation might behave differently in the product. Test in context.
3. Accessibility
Ensure all users can understand and interact with your errors. Verify:
- Does it carry the correct ARIA role so assistive technology recognizes it?
- Do screen readers announce it clearly?
- Does color contrast meet the minimum ratio (4.5)?
- Does it use more than color alone to indicate an error?
- Can keyboard-only users navigate to and through it?
- Does focus move to the error when it's critical?
- Is the text readable at 200% zoom?
- Are buttons and links large enough to tap (minimum 44×44 px)?
4. Edge cases
Test scenarios that commonly occur in production:
- Long file names — does truncation display correctly?
- Special characters in dynamic content — does everything render correctly?
- Multiple simultaneous errors — do they stack cleanly?
- Slow connections — does the error appear and remain readable?
- Internationalization — does the message work in supported languages?
- JavaScript disabled — can users still understand what happened?
- Low-performance devices — does the error render without breaking?
- Repeated errors — does the same error appearing multiple times degrade the experience?
Reference examples
The following examples show the original error messages from a SaaS data encryption application before revision.
Key principles
Error messages are a feature, not an afterthought. They directly affect user trust and support volume.
Every error needs four things: what happened, why it matters, what to do about it, and how to get help.
Write for users, log for developers. Never expose technical output in the UI, but always capture it in your logs.
Test with real people. A message that seems obvious to its author might be unclear to a first-time user.
Security and helpfulness can coexist. Be as helpful as possible without exposing system details that create risk.