- ⚡ Quick Start
- How It Works
- Step 1: Configure Settings
- Customizing the Email Design
- Step 2: Add Error Handler
- Debugging with Monitor
- Reference:
colErrorSignaturesCollection - Optional Enhancements
- Further Reading
📧 Get notified of every error without inbox overload — smart deduplication sends 2 emails instead of 60.
Power Apps can silently swallow errors, leaving users frustrated and developers blind to problems. This error handler catches every error in your canvas app and emails you a detailed report — but intelligently groups duplicate errors so you don't get flooded with 50 identical emails.
Whether it's a network timeout, a formula error, or a connector failure, you'll know about it immediately with full context: which screen, which control, the error message, and how many times it occurred.
| Step | Action | Where |
|---|---|---|
| 1 | Add Office365Outlook connector | Data → Add data |
| 2 | Copy configuration formulas | App.Formulas |
| 3 | Copy error handler code | App.OnError |
That's it! You'll receive email notifications for every unique error.
The error handler uses signature-based deduplication combined with a time-based cooldown to balance two needs:
- Don't flood your inbox when errors loop rapidly
- Do notify you again when errors recur later
flowchart TD
A[🔴 Error Occurs] --> B{Generate Signature<br/>Screen | Source | Message}
B --> C{Seen Before?}
C -->|No - New Error| D[Add to Collection<br/>Set LastEmailSentTime = Now]
D --> E[✅ SEND EMAIL]
C -->|Yes - Existing| F{Cooldown Elapsed?<br/>Now - LastEmailSentTime >= 10s}
F -->|No| G[Increment Counter Only<br/>❌ No Email]
F -->|Yes| H[Update LastEmailSentTime = Now]
H --> E
style A fill:#fee2e2
style E fill:#dcfce7
style G fill:#fef3c7
| Time | Event | Email Sent? | Why |
|---|---|---|---|
| 10:00:00 | Error A occurs (new) | ✅ Yes | First occurrence |
| 10:00:00.1 | Error A occurs again | ❌ No | Within 10s cooldown |
| 10:00:00.2 | Error A occurs again | ❌ No | Within 10s cooldown |
| 10:00:05 | Error A occurs again | ❌ No | Within 10s cooldown |
| 10:00:15 | Error A occurs again | ✅ Yes | Cooldown elapsed! |
| 10:00:16 | Error A occurs again | ❌ No | New cooldown started |
| Scenario | Without Cooldown | With 10s Cooldown |
|---|---|---|
| 100 errors in 1 second | 1 email | 1 email ✓ |
| Same error 5 seconds later | No email | No email ✓ |
| Same error 30 seconds later | No email | New email ✓ |
| Different error anytime | New email | New email ✓ |
💡 Configure the cooldown in
App.FormulaswithfxErrorEmailCooldownSeconds. Default is 10 seconds. Set to0to only email once per unique error (never re-email).
Copy to App.Formulas and update the highlighted values:
// ══════════════════════════════════════════════════════════════
// ERROR HANDLER SETTINGS
// ══════════════════════════════════════════════════════════════
// 📧 Who receives error emails (semicolon-separated for multiple)
fxErrorHandlerEmail = "YOUR_EMAIL_HERE";
// 📛 App name (shown in email subject/body)
fxApplicationName = "My Power App";
// 🔗 App URL (Player or Studio link from make.powerapps.com)
fxApplicationURL = "https://apps.powerapps.com/";
// ⏱️ Cooldown before same error can trigger another email (in seconds)
// After an email is sent for an error, wait this long before sending another
// for the same error. Prevents email floods while allowing recurring error alerts.
// Set to 0 to only email once per unique error (original behavior).
fxErrorEmailCooldownSeconds = 10;
// 🎨 Email theme colors (customize to match your brand)
fxEmailColors = {
HeaderBg: "#dc2626", // Red banner background
HeaderText: "#ffffff", // White header text
CardBg: "#ffffff", // White card background
CardBorder: "#e5e7eb", // Light gray border
TableHeaderBg: "#f9fafb", // Very light gray
TableHeaderText:"#374151", // Dark gray text
TableBorder: "#e5e7eb", // Light gray
CountBadgeBg: "#fef2f2", // Light red background
CountBadgeText: "#dc2626", // Red text
FooterBg: "#f3f4f6", // Light gray footer
FooterText: "#6b7280", // Medium gray
LinkColor: "#2563eb" // Blue links
};
// 📖 Error kind descriptions (for hover tooltips in email)
// See: https://learn.microsoft.com/en-us/power-platform/power-fx/reference/function-iferror#error-kinds
fxErrorKinds = [
{ KindName: "None", KindNumber: 0, Description: "There's no error." },
{ KindName: "Sync", KindNumber: 1, Description: "An error was reported by the data source. Check the Message column for more information." },
{ KindName: "MissingRequired", KindNumber: 2, Description: "A required field of a record was missing." },
{ KindName: "CreatePermission", KindNumber: 3, Description: "The user doesn't have create record permission for the data source." },
{ KindName: "EditPermissions", KindNumber: 4, Description: "The user doesn't have edit record permission for the data source." },
{ KindName: "DeletePermissions", KindNumber: 5, Description: "The user doesn't have delete record permission for the data source." },
{ KindName: "Conflict", KindNumber: 6, Description: "The record being updated has already been changed at the source." },
{ KindName: "NotFound", KindNumber: 7, Description: "Record couldn't be found." },
{ KindName: "ConstraintViolated", KindNumber: 8, Description: "The record didn't pass a constraint check on the server." },
{ KindName: "GeneratedValue", KindNumber: 9, Description: "A value was passed for a field that is auto-calculated by the server." },
{ KindName: "ReadOnlyValue", KindNumber: 10, Description: "Column is read only and can't be modified." },
{ KindName: "Validation", KindNumber: 11, Description: "The record didn't pass a validation check." },
{ KindName: "Unknown", KindNumber: 12, Description: "There was an error, but of an unknown kind." },
{ KindName: "Div0", KindNumber: 13, Description: "Division by zero." },
{ KindName: "BadLanguageCode", KindNumber: 14, Description: "An invalid or unrecognized language code was used." },
{ KindName: "BadRegex", KindNumber: 15, Description: "Invalid regular expression." },
{ KindName: "InvalidFunctionUsage", KindNumber: 16, Description: "Invalid usage of a function." },
{ KindName: "FileNotFound", KindNumber: 17, Description: "The SaveData storage couldn't be found." },
{ KindName: "AnalysisError", KindNumber: 18, Description: "System error. There was a problem with compiler analysis." },
{ KindName: "ReadPermission", KindNumber: 19, Description: "The user doesn't have read record permission for the data source." },
{ KindName: "NotSupported", KindNumber: 20, Description: "Operation not supported by this player or device." },
{ KindName: "InsufficientMemory", KindNumber: 21, Description: "There isn't enough memory or storage on the device." },
{ KindName: "QuotaExceeded", KindNumber: 22, Description: "Storage quota exceeded." },
{ KindName: "Network", KindNumber: 23, Description: "There was a problem with network communications." },
{ KindName: "Numeric", KindNumber: 24, Description: "A numeric function was used in an improper way." },
{ KindName: "InvalidArgument", KindNumber: 25, Description: "An invalid argument was passed to a function." },
{ KindName: "Internal", KindNumber: 26, Description: "System error. There was an internal problem with one of the functions." },
{ KindName: "NotApplicable", KindNumber: 27, Description: "No value is available." }
];
💡 Finding your App URL: Go to make.powerapps.com → Your App →
...→ Details → Web link
The error emails use a modern, professional template with color-coded badges and a card layout. You can customize the colors to match your brand using either method below.
An interactive HTML preview file is included so you can see and customize the email design in your browser:
- Open the preview: Open
email-template-preview.htmlin any web browser - See sample data: The preview shows 3 example errors so you can see how real emails will look
- Pick your colors: Use the color picker panel (top-right corner) to adjust:
- Header background color
- Count badge colors
- Button/link color
- Screen and Kind badge colors
- Export to PowerFx: Click "📋 Copy PowerFx Colors" to copy the
fxEmailColorscode - Paste in your app: Replace the
fxEmailColorsrecord in yourApp.Formulas
┌─────────────────────────────────────────────────────────────┐
│ email-template-preview.html │
│ ┌─────────────────────────────────────┐ ┌──────────────┐ │
│ │ │ │ 🎨 Colors │ │
│ │ Error Alert! │ │ [■] Header │ │
│ │ ┌─────────────────────────────┐ │ │ [■] Badge │ │
│ │ │ John Doe [3 errors] │ │ │ [■] Button │ │
│ │ │ ─────────────────────────── │ │ │ │ │
│ │ │ 47× │ HomeScreen │ Network │ │ │ [Copy Code] │ │
│ │ │ 12× │ Detail │ Sync │ │ └──────────────┘ │
│ │ └─────────────────────────────┘ │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
If you already know your brand colors, edit the fxEmailColors record directly:
| Property | What It Controls | Default |
|---|---|---|
HeaderBg |
Top banner background | #dc2626 (red) |
HeaderText |
Banner text color | #ffffff (white) |
CountBadgeBg |
Error count badge background | #fef2f2 (light red) |
CountBadgeText |
Error count badge text | #dc2626 (red) |
LinkColor |
"Open App" button | #2563eb (blue) |
CardBg |
Main card background | #ffffff (white) |
TableHeaderBg |
Table header row | #f9fafb (light gray) |
FooterBg |
Summary footer | #f3f4f6 (light gray) |
🔵 Blue Theme (Corporate)
fxEmailColors = {
HeaderBg: "#1e40af", // Blue banner
HeaderText: "#ffffff",
CardBg: "#ffffff",
CardBorder: "#e5e7eb",
TableHeaderBg: "#eff6ff", // Light blue
TableHeaderText:"#1e40af",
TableBorder: "#bfdbfe",
CountBadgeBg: "#dbeafe", // Light blue badge
CountBadgeText: "#1e40af",
FooterBg: "#f0f9ff",
FooterText: "#6b7280",
LinkColor: "#1e40af"
};
🟢 Green Theme (Success-focused)
fxEmailColors = {
HeaderBg: "#059669", // Green banner
HeaderText: "#ffffff",
CardBg: "#ffffff",
CardBorder: "#e5e7eb",
TableHeaderBg: "#ecfdf5", // Light green
TableHeaderText:"#065f46",
TableBorder: "#a7f3d0",
CountBadgeBg: "#d1fae5", // Light green badge
CountBadgeText: "#059669",
FooterBg: "#f0fdf4",
FooterText: "#6b7280",
LinkColor: "#059669"
};
🟣 Purple Theme (Modern)
fxEmailColors = {
HeaderBg: "#7c3aed", // Purple banner
HeaderText: "#ffffff",
CardBg: "#ffffff",
CardBorder: "#e5e7eb",
TableHeaderBg: "#f5f3ff", // Light purple
TableHeaderText:"#5b21b6",
TableBorder: "#c4b5fd",
CountBadgeBg: "#ede9fe", // Light purple badge
CountBadgeText: "#7c3aed",
FooterBg: "#faf5ff",
FooterText: "#6b7280",
LinkColor: "#7c3aed"
};
⬛ Dark Theme
fxEmailColors = {
HeaderBg: "#1f2937", // Dark gray banner
HeaderText: "#f9fafb",
CardBg: "#ffffff",
CardBorder: "#e5e7eb",
TableHeaderBg: "#f3f4f6",
TableHeaderText:"#1f2937",
TableBorder: "#d1d5db",
CountBadgeBg: "#374151", // Dark badge
CountBadgeText: "#f9fafb",
FooterBg: "#f9fafb",
FooterText: "#6b7280",
LinkColor: "#1f2937"
};
Copy to App.OnError — no modifications needed:
// ══════════════════════════════════════════════════════════════
// ERROR HANDLER - Paste into App.OnError (no changes needed)
// ══════════════════════════════════════════════════════════════
With(
{
ScreenName: App.ActiveScreen.Name,
MyUsersName: User().FullName,
MyUsersEmail: User().Email,
CurrentTime: Now(),
LightGrayColorHexBG: "background-color:" & fxLightGrayColor & ";",
CountBefore: CountRows(colErrorSignatures),
SubjectLine: Concatenate(
"Error(s) occurred in the ",
fxApplicationName,
" application for ",
User().FullName
)
},
// ═══════════════════════════════════════════════════════════════════════
// DIAGNOSTIC: Log incoming errors (view in Monitor tool)
// ═══════════════════════════════════════════════════════════════════════
Trace(
"ErrorHandler: START",
TraceSeverity.Information,
{
IncomingErrorCount: CountRows(AllErrors),
ExistingSignatureCount: CountBefore,
Screen: ScreenName,
User: MyUsersEmail
}
);
// Process each error - add new signatures or update existing counts
ForAll(
AllErrors As Err,
With(
{
// Generate unique signature: Screen|Source|Message
ErrSignature: ScreenName & "|" & Text(Err.Source) & "|" & Text(Err.Message),
IsNewError: IsBlank(LookUp(colErrorSignatures, Signature = ScreenName & "|" & Text(Err.Source) & "|" & Text(Err.Message)))
},
// ═══════════════════════════════════════════════════════════
// DIAGNOSTIC: Log each error being processed
// ═══════════════════════════════════════════════════════════
Trace(
"ErrorHandler: Processing Error",
TraceSeverity.Information,
{
Signature: ErrSignature,
IsNew: IsNewError,
Kind: Text(Err.Kind),
Message: Text(Err.Message)
}
);
If(
IsNewError,
// ═══════════════════════════════════════════════════════════
// NEW UNIQUE ERROR - Add to tracking collection
// ═══════════════════════════════════════════════════════════
Collect(
colErrorSignatures,
{
Signature: ErrSignature,
Screen: ScreenName,
Source: Text(Err.Source),
Kind: Text(Err.Kind),
Message: Text(Err.Message),
Observed: Text(Err.Observed),
HttpResponse: Text(Err.Details.HttpResponse),
HttpStatusCode: Text(Err.Details.HttpStatusCode),
Occurrences: 1,
FirstOccurrence: Text(CurrentTime, "MM/dd/yyyy hh:mm:ss AM/PM"),
LastOccurrence: Text(CurrentTime, "MM/dd/yyyy hh:mm:ss AM/PM"),
LastEmailSentTime: CurrentTime, // Track when email was sent for cooldown
UserEmail: MyUsersEmail,
UsersName: MyUsersName
}
),
// ═══════════════════════════════════════════════════════════
// EXISTING ERROR - Increment counter, check cooldown for re-email
// ═══════════════════════════════════════════════════════════
With(
{
ExistingRecord: LookUp(colErrorSignatures, Signature = ErrSignature),
CooldownElapsed: fxErrorEmailCooldownSeconds > 0 And
DateDiff(
LookUp(colErrorSignatures, Signature = ErrSignature).LastEmailSentTime,
CurrentTime,
TimeUnit.Seconds
) >= fxErrorEmailCooldownSeconds
},
Patch(
colErrorSignatures,
ExistingRecord,
{
Occurrences: ExistingRecord.Occurrences + 1,
LastOccurrence: Text(CurrentTime, "MM/dd/yyyy hh:mm:ss AM/PM"),
// Update LastEmailSentTime if cooldown elapsed (triggers email)
LastEmailSentTime: If(CooldownElapsed, CurrentTime, ExistingRecord.LastEmailSentTime)
}
)
)
)
)
);
// ═══════════════════════════════════════════════════════════════════════
// DIAGNOSTIC: Log collection state before email decision
// ═══════════════════════════════════════════════════════════════════════
Trace(
"ErrorHandler: Pre-Email Check",
TraceSeverity.Information,
{
CountBefore: CountBefore,
CountAfter: CountRows(colErrorSignatures),
NewErrorsAdded: CountRows(colErrorSignatures) - CountBefore,
ErrorsNeedingEmail: CountIf(colErrorSignatures, LastEmailSentTime = CurrentTime),
WillSendEmail: CountIf(colErrorSignatures, LastEmailSentTime = CurrentTime) > 0,
TotalOccurrences: Sum(colErrorSignatures, Occurrences)
}
);
// ═══════════════════════════════════════════════════════════════════════
// SEND EMAIL IF: New error added OR existing error's cooldown elapsed
// (Any error with LastEmailSentTime = CurrentTime triggers email)
// ═══════════════════════════════════════════════════════════════════════
If(
CountIf(colErrorSignatures, LastEmailSentTime = CurrentTime) > 0,
// ═══════════════════════════════════════════════════════════════════════
// DIAGNOSTIC: Log email content details
// ═══════════════════════════════════════════════════════════════════════
Trace(
"ErrorHandler: Sending Email",
TraceSeverity.Warning,
{
To: fxErrorHandlerEmail,
Subject: SubjectLine,
UniqueErrorCount: CountRows(colErrorSignatures),
ErrorSummary: Concat(colErrorSignatures, ThisRecord.Screen & ": " & ThisRecord.Message & " (" & ThisRecord.Occurrences & "×)", ", ")
}
);
Office365Outlook.SendEmailV2(
fxErrorHandlerEmail,
SubjectLine,
$"<html>
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
</head>
<body style='margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background-color:#f3f4f6;'>
<!-- Header Banner -->
<table width='100%' cellpadding='0' cellspacing='0' style='background-color:{fxEmailColors.HeaderBg};'>
<tr>
<td style='padding:24px 32px;'>
<table width='100%' cellpadding='0' cellspacing='0'>
<tr>
<td>
<span style='font-size:28px;'>⚠️</span>
<span style='color:{fxEmailColors.HeaderText};font-size:22px;font-weight:600;margin-left:12px;vertical-align:middle;'>
Error Alert
</span>
</td>
<td style='text-align:right;'>
<span style='color:{fxEmailColors.HeaderText};font-size:14px;opacity:0.9;'>
{Text(CurrentTime, ""mmm dd, yyyy · hh:mm AM/PM"")}
</span>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!-- Main Content Card -->
<table width='100%' cellpadding='0' cellspacing='0' style='padding:24px;'>
<tr>
<td>
<table width='100%' cellpadding='0' cellspacing='0' style='background-color:{fxEmailColors.CardBg};border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.1);overflow:hidden;'>
<!-- User Info -->
<tr>
<td style='padding:24px 24px 16px 24px;border-bottom:1px solid {fxEmailColors.CardBorder};'>
<table width='100%' cellpadding='0' cellspacing='0'>
<tr>
<td>
<div style='font-size:18px;font-weight:600;color:#111827;margin-bottom:4px;'>
{MyUsersName}
</div>
<div style='font-size:14px;color:#6b7280;'>
{MyUsersEmail}
</div>
</td>
<td style='text-align:right;vertical-align:top;'>
<span style='display:inline-block;background-color:{fxEmailColors.CountBadgeBg};color:{fxEmailColors.CountBadgeText};font-size:14px;font-weight:600;padding:6px 12px;border-radius:20px;'>
{CountRows(colErrorSignatures)} unique error{If(CountRows(colErrorSignatures)>1,""s"","""")}
</span>
</td>
</tr>
</table>
</td>
</tr>
<!-- Error Table -->
<tr>
<td style='padding:0;'>
<table width='100%' cellpadding='0' cellspacing='0' style='border-collapse:collapse;'>
<tr style='background-color:{fxEmailColors.TableHeaderBg};'>
<th style='padding:12px 16px;text-align:center;font-size:12px;font-weight:600;color:{fxEmailColors.TableHeaderText};text-transform:uppercase;letter-spacing:0.5px;border-bottom:2px solid {fxEmailColors.TableBorder};width:70px;'>Count</th>
<th style='padding:12px 16px;text-align:left;font-size:12px;font-weight:600;color:{fxEmailColors.TableHeaderText};text-transform:uppercase;letter-spacing:0.5px;border-bottom:2px solid {fxEmailColors.TableBorder};'>Screen</th>
<th style='padding:12px 16px;text-align:left;font-size:12px;font-weight:600;color:{fxEmailColors.TableHeaderText};text-transform:uppercase;letter-spacing:0.5px;border-bottom:2px solid {fxEmailColors.TableBorder};'>Kind</th>
<th style='padding:12px 16px;text-align:left;font-size:12px;font-weight:600;color:{fxEmailColors.TableHeaderText};text-transform:uppercase;letter-spacing:0.5px;border-bottom:2px solid {fxEmailColors.TableBorder};'>Source</th>
<th style='padding:12px 16px;text-align:left;font-size:12px;font-weight:600;color:{fxEmailColors.TableHeaderText};text-transform:uppercase;letter-spacing:0.5px;border-bottom:2px solid {fxEmailColors.TableBorder};'>Message</th>
<th style='padding:12px 16px;text-align:right;font-size:12px;font-weight:600;color:{fxEmailColors.TableHeaderText};text-transform:uppercase;letter-spacing:0.5px;border-bottom:2px solid {fxEmailColors.TableBorder};width:140px;'>Timestamps</th>
</tr>" &
Concat(
colErrorSignatures,
$"<tr style='border-bottom:1px solid {fxEmailColors.TableBorder};'>
<td style='padding:16px;text-align:center;vertical-align:top;'>
<span style='display:inline-block;background-color:{fxEmailColors.CountBadgeBg};color:{fxEmailColors.CountBadgeText};font-size:16px;font-weight:700;padding:8px 14px;border-radius:8px;min-width:40px;'>
{ThisRecord.Occurrences}×
</span>
</td>
<td style='padding:16px;vertical-align:top;'>
<span style='display:inline-block;background-color:#dbeafe;color:#1e40af;font-size:13px;font-weight:500;padding:4px 10px;border-radius:6px;'>
{ThisRecord.Screen}
</span>
</td>
<td style='padding:16px;vertical-align:top;'>
<span style='display:inline-block;background-color:#fef3c7;color:#92400e;font-size:13px;font-weight:500;padding:4px 10px;border-radius:6px;' title='{Substitute(LookUp(fxErrorKinds, KindName = ThisRecord.Kind, Description), "'", "'")}'>
{ThisRecord.Kind}
</span>
</td>
<td style='padding:16px;vertical-align:top;font-size:14px;color:#374151;font-family:ui-monospace,monospace;'>
{ThisRecord.Source}
</td>
<td style='padding:16px;vertical-align:top;font-size:14px;color:#111827;max-width:300px;'>
{ThisRecord.Message}
</td>
<td style='padding:16px;vertical-align:top;text-align:right;'>
<div style='font-size:12px;color:#6b7280;margin-bottom:4px;'>
<strong>First:</strong> {ThisRecord.FirstOccurrence}
</div>
<div style='font-size:12px;color:#6b7280;'>
<strong>Last:</strong> {ThisRecord.LastOccurrence}
</div>
</td>
</tr>"
) & $"
</table>
</td>
</tr>
<!-- Summary Footer -->
<tr>
<td style='padding:20px 24px;background-color:{fxEmailColors.FooterBg};border-top:1px solid {fxEmailColors.CardBorder};'>
<table width='100%' cellpadding='0' cellspacing='0'>
<tr>
<td>
<span style='font-size:14px;color:{fxEmailColors.FooterText};'>
<strong style='color:#374151;'>{CountRows(colErrorSignatures)}</strong> unique errors ·
<strong style='color:#374151;'>{Sum(colErrorSignatures, Occurrences)}</strong> total occurrences
</span>
</td>
<td style='text-align:right;'>
<a href='{fxApplicationURL}' style='display:inline-block;background-color:{fxEmailColors.LinkColor};color:#ffffff;font-size:14px;font-weight:500;padding:10px 20px;border-radius:8px;text-decoration:none;'>
Open {fxApplicationName}
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!-- Footer -->
<table width='100%' cellpadding='0' cellspacing='0'>
<tr>
<td style='padding:16px 24px 32px 24px;text-align:center;'>
<div style='font-size:12px;color:#9ca3af;'>
Automated error report from {fxApplicationName}
</div>
</td>
</tr>
</table>
</body>
</html>"
)
);
);
The error handler logs to Power Apps Monitor so you can see exactly what's happening.
To open Monitor: Power Apps Studio → Advanced tools (Alt+T) → Monitor → Play your app
| Trace Event | What It Shows |
|---|---|
ErrorHandler: START |
How many errors came in, current screen, user |
ErrorHandler: Processing Error |
Each error's signature and whether it's new |
ErrorHandler: Pre-Email Check |
Will an email be sent? How many new errors? |
ErrorHandler: Sending Email |
Email recipient, subject, error summary |
📋 Example Monitor Output
[Information] ErrorHandler: START
IncomingErrorCount: 3, Screen: "HomeScreen", User: "user@domain.com"
[Information] ErrorHandler: Processing Error
Signature: "HomeScreen|Button1.OnSelect|Network error"
IsNew: true, Kind: "Network"
[Information] ErrorHandler: Pre-Email Check
CountBefore: 0, CountAfter: 1
ErrorsNeedingEmail: 1, WillSendEmail: true
[Warning] ErrorHandler: Sending Email
To: "admin@domain.com"
UniqueErrorCount: 1
ErrorSummary: "HomeScreen: Network error (1×)"
Cooldown in action:
[Information] ErrorHandler: Pre-Email Check
CountBefore: 1, CountAfter: 1
ErrorsNeedingEmail: 0, WillSendEmail: false ← Same error, still in cooldown
[Information] ErrorHandler: Pre-Email Check
CountBefore: 1, CountAfter: 1
ErrorsNeedingEmail: 1, WillSendEmail: true ← Cooldown elapsed, re-sending!
💡 For production: Remove the
Trace()statements to declutter your Monitor.
The error handler automatically creates this collection to track errors:
| Field | Type | Description |
|---|---|---|
Signature |
Text | Unique key: Screen|Source|Message |
Screen |
Text | Where the error occurred |
Source |
Text | Control or function that caused it |
Kind |
Text | Error type (Sync, Network, etc.) |
Message |
Text | The error message |
Occurrences |
Number | How many times this error happened |
FirstOccurrence / LastOccurrence |
Text | Timestamps (formatted strings) |
LastEmailSentTime |
DateTime | When an email was last sent for this error |
UserEmail / UsersName |
Text | Who triggered the error |
HttpResponse / HttpStatusCode |
Text | API details (if applicable) |
Add a gallery bound to colErrorSignatures on a debug screen:
// Gallery.Items
colErrorSignatures
// Label formulas
ThisItem.Occurrences & "× - " & ThisItem.Message
Add to App.OnStart for a fresh collection each session:
Clear(colErrorSignatures);
📋 Click to expand persistence code
Create a table/list with columns matching the collection fields, then add to a "Save & Exit" button:
ForAll(
colErrorSignatures,
Patch(
PowerAppsErrors, // Your data source
Defaults(PowerAppsErrors),
{
Signature: Signature,
Screen: Screen,
Source: Source,
Kind: Kind,
Message: Message,
Occurrences: Occurrences,
FirstOccurrence: FirstOccurrence,
LastOccurrence: LastOccurrence,
UserEmail: UserEmail,
UsersName: UsersName
}
)
);
Clear(colErrorSignatures);
| Date | Author | Changes |
|---|---|---|
| 2025-12-18 | Claude Opus 4.5 | Added hover tooltips on Kind badges showing error description via fxErrorKinds LookUp |
| 2025-12-18 | Claude Opus 4.5 | Added fxErrorKinds named formula with all 28 error kinds and descriptions |
| 2025-12-18 | Claude Opus 4.5 | Fixed Mermaid diagram parse error by escaping pipe characters with | HTML entities |
| 2025-12-18 | Claude Opus 4.5 | Added time-based cooldown feature with fxErrorEmailCooldownSeconds config (default 10s) |
| 2025-12-18 | Claude Opus 4.5 | Added LastEmailSentTime field to collection for cooldown tracking |
| 2025-12-18 | Claude Opus 4.5 | Rewrote "How It Works" section with Mermaid flowchart and cooldown examples |
| 2025-12-17 | Claude Opus 4.5 | Added "Customizing the Email Design" section with visual preview instructions and 4 theme examples |
| 2025-12-17 | Claude Opus 4.5 | Redesigned email template with modern styling: header banner, color-coded badges, card layout |
| 2025-12-17 | Claude Opus 4.5 | Added fxEmailColors record for customizable email theming |
| 2025-12-17 | Claude Opus 4.5 | Created email-template-preview.html for live preview and color customization |
| 2025-12-17 | Claude Opus 4.5 | Rewrote documentation for clarity: added quick-start, visual flow diagram, collapsible sections |
| 2025-12-17 | Claude Opus 4.5 | Added diagnostic logging with Trace() statements |
| 2025-12-17 | Claude Opus 4.5 | Fixed multi-row email output with explicit ThisRecord references |
| 2025-12-04 | Claude Opus 4.5 | Implemented v2.2 with signature-based deduplication |
| 2025-12-04 | Claude Opus 4.5 | Added occurrence counting and full session reports |