Skip to main content
RapidDev - Software Development Agency
outsystems-tutorial

Error Handling Patterns: From Exception Types to Production Logging

Add exception handlers to action flows by right-clicking any node → Add Exception Handler. Choose the most specific exception type (User, Database, Communication, Security) before AllExceptions. Log errors to Service Center using the LogMessage or LogError built-in actions. Always show user-friendly Feedback Messages rather than raw exception details.

What you'll learn

  • The five OutSystems exception types and when each is triggered
  • How to add exception handlers in both Client Actions and Server Actions
  • Logging errors to Service Center using LogMessage and LogError actions
  • Showing user-friendly feedback messages instead of raw error details
  • Structuring a global exception handling strategy for production applications
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate9 min read30-40 minOutSystems 11 and ODCMarch 2026RapidDev Engineering Team
TL;DR

Add exception handlers to action flows by right-clicking any node → Add Exception Handler. Choose the most specific exception type (User, Database, Communication, Security) before AllExceptions. Log errors to Service Center using the LogMessage or LogError built-in actions. Always show user-friendly Feedback Messages rather than raw exception details.

Error Handling in OutSystems

Unhandled exceptions in OutSystems display an ugly system error page to users and leave no trace in logs unless you explicitly handle and record them. This tutorial covers the full error handling lifecycle: catching exceptions at the right level, logging useful diagnostic information, and presenting user-friendly error messages. The patterns apply to both Client Actions (browser-side) and Server Actions (server-side).

Prerequisites

  • A Reactive Web App with at least one Server Action and one Client Action that calls it
  • Service Studio open with the Logic tab visible
  • Basic familiarity with action flows and the Action Flow Editor

Step-by-step guide

1

Understand the five exception types

OutSystems has a hierarchy of exception types. Handlers are matched from most specific to least specific: 1. User Exception — custom business exceptions you define and raise with the Raise Exception node. Example: 'InvalidOrderAmount', 'CustomerBlocked'. 2. Database Exception — database constraint violations (FK violation, unique index, NOT NULL breach), connection errors. Triggered automatically by the platform. 3. Communication Exception — network failures when calling REST/SOAP APIs, server timeouts, unreachable servers. 4. Security Exception — unauthorized access, role check failures, invalid sessions. 5. AllExceptions — catches anything not caught by a more specific handler above it. Best practice: always handle the most specific type you expect, then add an AllExceptions handler as a safety net. Handling AllExceptions alone swallows Database and Communication exceptions without distinguishing them. To define a custom User Exception: Logic tab → Exceptions → right-click → Add Exception. Name it (e.g. 'InvalidAmount'). Set BuiltIn = No.

Expected result: You can identify which exception type will be raised by any given failure scenario in your app.

2

Add an exception handler to a Server Action

Open SaveEmployee Server Action in the Action Flow Editor (Logic tab → Server Actions → double-click). Right-click any node in the flow (e.g., the CreateEmployee entity action) → 'Add Exception Handler'. A handler connector appears from the node to an Exception Handler node at the bottom of the flow. In the Exception Handler node Properties Panel, set: - Exception: Database Exception - Abort Transaction: Yes (rolls back any uncommitted DB changes) Inside the handler: Start (handler) → LogError ('SaveEmployee failed', ExceptionMessage) → Raise User Exception 'SaveFailed' with message 'Employee could not be saved. Please try again.' → End By raising a User Exception from inside the handler, you convert a technical Database Exception into a business-level exception that the Client Action above can catch with a friendly message.

typescript
1/* Exception handler flow inside SaveEmployee */
2Exception Handler (Database Exception, Abort: Yes)
3 --> LogError:
4 ModuleName = "HRModule"
5 Source = "SaveEmployee"
6 Message = "DB error saving employee: " + ExceptionMessage
7 --> Raise Exception: SaveFailed
8 Message = "Employee could not be saved. Please try again."
9 --> End

Expected result: When a database constraint fails (e.g., duplicate email), the handler fires, logs the technical error, and raises a clean SaveFailed User Exception up the call stack.

3

Catch the re-raised exception in the Client Action

In the Client Action that calls SaveEmployee (e.g., SubmitFormOnClick), add an exception handler for the SaveFailed User Exception. In the Client Action flow, right-click the SaveEmployee call node → 'Add Exception Handler'. Set Exception = SaveFailed (User Exception). Inside the handler: Exception Handler (SaveFailed) --> Message: ExceptionMessage (Warning type) --> End (flow ends here, not navigating away) The ExceptionMessage variable is automatically available inside exception handlers — it holds the message string from the Raise Exception node. For handling all unexpected errors, add a second handler: right-click anywhere in the flow → 'Add Exception Handler' → set to AllExceptions. This catches anything SaveEmployee did not already handle.

typescript
1/* Client Action: SubmitFormOnClick */
2Start
3 --> SaveEmployee: FullName, DepartmentId
4 --> Destination: EmployeeListScreen
5 --> End
6
7/* Exception handler attached to SaveEmployee node: */
8Exception Handler (User Exception: SaveFailed)
9 --> Message: ExceptionMessage (MessageType = Warning)
10 --> End
11
12/* Fallback: */
13Exception Handler (AllExceptions)
14 --> Message: "An unexpected error occurred. Our team has been notified." (Error)
15 --> End

Expected result: A database error during save shows the user a clear warning message instead of a system crash page. The unexpected error handler catches anything else.

4

Log errors to Service Center with LogMessage and LogError

OutSystems provides two built-in logging actions in Logic tab → System: - LogMessage(ModuleName, Source, Message): writes to the General log in Service Center. Use for informational events and warnings. - LogError(ModuleName, Source, Message, AdditionalData): writes to the Error log with full stack trace context. Use for all caught exceptions. To use LogError: drag it from Logic tab → System → Logging into the exception handler flow before re-raising or showing the message to the user. In Service Center: Monitoring → Error Logs (shows LogError entries) or Monitoring → General Logs (shows LogMessage entries). Each entry includes timestamp, module, user, environment, and message. Best practice log format: Module='HRModule', Source='SaveEmployee', Message='DB exception: ' + ExceptionMessage + ' | UserId: ' + IntegerToText(GetUserId()) + ' | Input: ' + FullName

typescript
1/* LogError call inside exception handler */
2LogError:
3 ModuleName = "HRModule"
4 Source = "SaveEmployee"
5 Message = "DB exception saving employee"
6 AdditionalData = "User: " + IntegerToText(GetUserId())
7 + " | Name: " + FullName
8 + " | Error: " + ExceptionMessage

Expected result: After triggering an error, you can see the detailed log entry in Service Center → Monitoring → Error Logs with user context and the original exception message.

5

Create a global error handler screen for unhandled exceptions

For errors that escape all local handlers (e.g., an unhandled exception in a screen's OnInitialize action), OutSystems redirects to a default error page. You can customize this. In the Interface tab, create a new Screen named 'GlobalErrorScreen'. Set its Role access to Anonymous so any user can see it. In Service Studio: Logic tab → Exceptions → set the Error Handler property of your module to GlobalErrorScreen. Alternatively, in the Interface tab select your UI Flow → Properties Panel → set Error Handler to GlobalErrorScreen. Any unhandled exception in screens within that UI Flow will redirect here. On GlobalErrorScreen: show a user-friendly message ('Something went wrong. Please go back or contact support.') and a button to navigate to Home. Do NOT display the raw ExceptionMessage on this screen — it exposes internal details.

Expected result: Intentionally removing an exception handler and triggering an error redirects users to your branded GlobalErrorScreen instead of the OutSystems default error page.

Complete working example

ErrorHandling_patterns.txt
1/* ============================================================
2 EXCEPTION DEFINITIONS (Logic tab Exceptions)
3 - SaveFailed : User Exception
4 - ValidationError : User Exception
5 ============================================================ */
6
7/* ============================================================
8 SERVER ACTION: SaveEmployee
9 Exception handling: Database Exception log re-raise
10 ============================================================ */
11Start
12 --> Aggregate: GetEmployeeByEmail (check for duplicates)
13 --> If: not GetEmployeeByEmail.List.Empty
14 [True] --> Raise Exception: ValidationError
15 Message = "An employee with this email already exists."
16 --> CreateEmployee: Employee.FullName=FullName, Employee.Email=Email
17 --> Assign: EmployeeId = CreateEmployee.Id
18 --> End
19
20Exception Handler (Database Exception, Abort: Yes)
21 --> LogError:
22 ModuleName = "HRModule"
23 Source = "SaveEmployee"
24 Message = ExceptionMessage
25 AdditionalData = "Email: " + Email
26 --> Raise Exception: SaveFailed
27 Message = "Could not save employee. Please try again."
28 --> End
29
30/* ============================================================
31 CLIENT ACTION: ButtonSubmitOnClick
32 ============================================================ */
33Start
34 --> (validation logic)
35 --> If: Form.Valid
36 [True] --> SaveEmployee: FullName=FullName, Email=Email
37 --> Destination: EmployeeListScreen
38 [False]--> End
39 --> End
40
41Exception Handler (User Exception: ValidationError)
42 --> Message: ExceptionMessage (Warning)
43 --> End
44
45Exception Handler (User Exception: SaveFailed)
46 --> Message: ExceptionMessage (Warning)
47 --> End
48
49Exception Handler (AllExceptions)
50 --> Message: "An unexpected error occurred. Our team has been notified." (Error)
51 --> End

Common mistakes

Why it's a problem: Using only AllExceptions and not distinguishing Database from Communication exceptions

How to avoid: Add specific handlers for Database Exception and Communication Exception first, with appropriate logic (rollback for DB, retry message for network). Use AllExceptions only as a final fallback.

Why it's a problem: Catching an exception in a Server Action but not logging or re-raising — silently swallowing it

How to avoid: An empty exception handler (handler → End) hides errors completely. Always either log the error, re-raise a meaningful exception, or at minimum show an output flag indicating failure to the caller.

Why it's a problem: Placing LogError inside a Client Action exception handler for server-side errors

How to avoid: LogError from a Client Action writes to the browser console, not Service Center. Log server-side errors in Server Action exception handlers before re-raising. Client Action handlers should only handle User Exceptions that bubbled up from server calls.

Why it's a problem: Not setting Abort Transaction = Yes in a Database Exception handler that catches a partial write

How to avoid: Without Abort Transaction, partial writes made before the exception may be committed. Set Abort Transaction = Yes in any handler where database integrity could be compromised.

Best practices

  • Always log the ExceptionMessage in server-side exception handlers before showing a user-friendly message — raw technical details belong in logs, not in the UI.
  • Handle the most specific exception type (Database, Communication) before the general AllExceptions handler in the same action.
  • Set Abort Transaction = Yes in Database Exception handlers to prevent partial data commits.
  • Re-raise a User Exception from a Server Action's Database Exception handler so the calling Client Action receives a business-level error it can display meaningfully.
  • Never display ExceptionMessage directly to end users on error screens — it may expose internal table names, SQL fragments, or stack traces.
  • Test your exception handlers by intentionally triggering the error condition in the Debugger (Processes tab → Debugger) to verify the handler fires correctly.

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

Explain OutSystems exception handling for a Reactive Web App. I have a Server Action SaveEmployee that writes to the database. Show me how to: (1) add a Database Exception handler with Abort Transaction and LogError, (2) re-raise a custom SaveFailed User Exception, (3) catch SaveFailed in the calling Client Action and show a warning Message, (4) add an AllExceptions fallback. Use OutSystems action flow arrow notation.

OutSystems Prompt

Add error handling to my OutSystems SaveEmployee Server Action. Create a Database Exception handler with Abort Transaction = Yes that calls LogError (ModuleName='HRModule', Source='SaveEmployee', Message=ExceptionMessage) and then raises a SaveFailed User Exception with message 'Could not save employee. Please try again.' In the calling Client Action ButtonSubmitOnClick, add a SaveFailed handler showing ExceptionMessage as a Warning Message, and an AllExceptions handler showing a generic error message.

Frequently asked questions

What is the difference between LogMessage and LogError in OutSystems?

LogMessage writes to the General log in Service Center and is for informational events (workflow started, record processed). LogError writes to the Error log with a higher severity level and is specifically for caught exceptions. Both are in Logic tab → System → Logging. Use LogError for all exception handlers.

Can I catch exceptions in a Data Action?

Yes. Data Actions run server-side and support the same exception handler mechanism as Server Actions. Right-click any node in a Data Action flow → Add Exception Handler. Unhandled Data Action exceptions cause the screen's data-fetch to fail silently — always add at least an AllExceptions handler in Data Actions used in production.

How do I handle exceptions differently in development vs production without changing code?

Use a Site Property 'IsDebugMode' (Boolean, set True in Dev, False in Prod). In AllExceptions handlers, check If IsDebugMode then show ExceptionMessage in the feedback message, else show the generic message. Change the Site Property value per environment in Service Center without redeploying.

Does ODC have a different logging mechanism than O11?

ODC uses the same LogMessage and LogError actions in your action flows, but logs are viewed in ODC Portal → Monitoring → Traces instead of Service Center. The action signatures and behavior are identical. ODC also provides structured logging with automatic correlation IDs for distributed tracing.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.