Exceptions and Error Handling

View as Markdown

NeMo Guardrails supports raising exceptions from within flows. An exception is an event whose name ends with Exception, e.g., InputRailException. When an exception is raised, the final output is a message with the role set to exception and the content set to additional information about the exception. For example:

define flow input rail example
# ...
create event InputRailException(message="Input not allowed.")
1{
2 "role": "exception",
3 "content": {
4 "type": "InputRailException",
5 "uid": "45a452fa-588e-49a5-af7a-0bab5234dcc3",
6 "event_created_at": "9999-99-99999:24:30.093749+00:00",
7 "source_uid": "NeMoGuardrails",
8 "message": "Input not allowed."
9 }
10}

Guardrails Library Exception

By default, all the guardrails included in the Guardrail Catalog return a predefined message when a rail is triggered. You can change this behavior by setting the enable_rails_exceptions key to True in your config.yml file:

1enable_rails_exceptions: True

When this setting is enabled, the rails are triggered, they will return an exception message. To understand better what is happening under the hood, here’s how the self check input rail is implemented:

define flow self check input
$allowed = execute self_check_input
if not $allowed
if $config.enable_rails_exceptions
create event InputRailException(message="Input not allowed. The input was blocked by the 'self check input' flow.")
else
bot refuse to respond
stop

In Colang 2.x, you must change $config.enable_rails_exceptions to $system.config.enable_rails_exceptions and create event to send.

When the self check input rail is triggered, the following exception is returned.

1{
2 "role": "exception",
3 "content": {
4 "type": "InputRailException",
5 "uid": "45a452fa-588e-49a5-af7a-0bab5234dcc3",
6 "event_created_at": "9999-99-99999:24:30.093749+00:00",
7 "source_uid": "NeMoGuardrails",
8 "message": "Input not allowed. The input was blocked by the 'self check input' flow."
9 }
10}

Exception Types

The NeMo Guardrails library includes additional exception types for specific integrations:

  • LlamaGuardInputRailException / LlamaGuardOutputRailException
  • JailbreakDetectionRailException
  • ContentSafetyCheckInputException / ContentSafetyCheckOutputException
  • FactCheckRailException
  • SelfCheckHallucinationRailException
  • InjectionDetectionRailException

Each library rail raises its own exception type when enable_rails_exceptions is enabled.


Custom Exception Handling

You can create custom exception types by following the naming convention of ending with Exception:

define flow custom validation
if not $custom_condition
create event CustomValidationException(message="Custom validation failed.")

Exception Response Format

All exceptions follow a consistent JSON format:

1{
2 "role": "exception",
3 "content": {
4 "type": "ExceptionType",
5 "uid": "unique-identifier",
6 "event_created_at": "timestamp",
7 "source_uid": "source-identifier",
8 "message": "Human-readable error message"
9 }
10}

Field Descriptions

  • type: The exception type (e.g., InputRailException)
  • uid: A unique identifier for the exception instance
  • event_created_at: Timestamp when the exception was created
  • source_uid: Identifier for the source that created the exception
  • message: Human-readable description of what went wrong

Handling Exceptions in Applications

When integrating NeMo Guardrails with your application, you should handle exceptions appropriately:

1from nemoguardrails import LLMRails, RailsConfig
2
3config = RailsConfig.from_path("./config")
4rails = LLMRails(config)
5
6try:
7 response = rails.generate(messages=[{"role": "user", "content": "Hello"}])
8
9 if response.get("role") == "exception":
10 # Handle the exception
11 exception_content = response.get("content", {})
12 exception_type = exception_content.get("type")
13 exception_message = exception_content.get("message")
14
15 # Log the exception or take appropriate action
16 print(f"Exception {exception_type}: {exception_message}")
17
18 # Provide fallback response to user
19 fallback_response = "I'm sorry, but I cannot process that request at the moment."
20 else:
21 # Process normal response
22 print(response.get("content", ""))
23
24except Exception as e:
25 # Handle other errors
26 print(f"Error: {e}")

Best Practices

  1. Use Descriptive Messages: Provide clear, actionable error messages in your exceptions.

  2. Log Exceptions: Always log exceptions for debugging and monitoring purposes.

  3. Graceful Degradation: Provide fallback responses when exceptions occur.

  4. User-Friendly Messages: Translate technical exception messages into user-friendly responses.

  5. Exception Categories: Use appropriate exception types to categorize different kinds of errors.

  6. Configuration Control: Use the enable_rails_exceptions setting to control whether rails return exceptions or predefined messages.