AL Error Handling & Troubleshooting Rules
AL Error Handling & Troubleshooting Rules
Robust error handling and effective troubleshooting practices are essential for maintaining reliable Business Central applications.
Rule 1: Use TryFunctions for Error Handling
Intent
Implement proper error handling using TryFunctions to manage exceptions gracefully and provide meaningful user feedback. Use TryFunctions for error handling in scenarios where rollback is required, implement proper exception handling for external service calls, provide meaningful error messages to users, and log errors appropriately for debugging purposes. When generating code that might fail (external calls, data operations, calculations), implement appropriate TryFunction error handling and provide clear error messages.
Examples
// Good example - TryFunction with proper error handling and error labels
procedure ProcessPayment(Amount: Decimal): Boolean
var
PaymentService: Codeunit "Payment Service";
ErrorText: Text;
PaymentProcessingFailedLbl: Label 'Payment processing failed: %1', Comment = '%1 = Error message';
PaymentProcessingFailedTelemetryLbl: Label 'Payment processing failed', Locked = true;
begin
if not TryProcessPaymentInternal(Amount) then begin
ErrorText := GetLastErrorText();
LogError(PaymentProcessingFailedTelemetryLbl, ErrorText);
Message(PaymentProcessingFailedLbl, ErrorText);
exit(false);
end;
exit(true);
end;
[TryFunction]
local procedure TryProcessPaymentInternal(Amount: Decimal)
var
PaymentService: Codeunit "Payment Service";
begin
PaymentService.ProcessPayment(Amount);
end;
// Bad example (avoid hardcoded error messages and unhandled errors)
procedure ProcessPayment(Amount: Decimal)
var
PaymentService: Codeunit "Payment Service";
begin
// No error handling - will cause unhandled exceptions
// Also avoid hardcoded messages like this:
// Message('Payment could not be processed');
PaymentService.ProcessPayment(Amount);
end;
Rule 2: Use Error Labels for All Messages
Intent
All error messages, warnings, and user messages must use label variables instead of hardcoded text. This ensures proper localization support and maintainability. Define labels with appropriate comments for translators and use Locked = true for technical messages that should not be translated.
Examples
// Good example - Using error labels
procedure ValidateBusinessLogic(SalesHeader: Record "Sales Header")
var
Customer: Record Customer;
CustomerNotFoundErr: Label 'Customer %1 does not exist for sales document %2.', Comment = '%1 = Customer No., %2 = Sales Header No.';
CustomerBlockedErr: Label 'Customer %1 is blocked (%2). Cannot process sales document %3.', Comment = '%1 = Customer No., %2 = Blocked reason, %3 = Sales Header No.';
EmptyHeaderNoErr: Label 'Sales header number cannot be empty.';
begin
if SalesHeader."No." = '' then
Error(EmptyHeaderNoErr);
if not Customer.Get(SalesHeader."Sell-to Customer No.") then
Error(CustomerNotFoundErr, SalesHeader."Sell-to Customer No.", SalesHeader."No.");
if Customer.Blocked <> Customer.Blocked::" " then
Error(CustomerBlockedErr, Customer."No.", Customer.Blocked, SalesHeader."No.");
end;
// Bad example (avoid hardcoded error messages)
procedure ValidateBusinessLogic(SalesHeader: Record "Sales Header")
var
Customer: Record Customer;
begin
if not Customer.Get(SalesHeader."Sell-to Customer No.") then
Error('Customer not found'); // Hardcoded - avoid this
if Customer.Blocked <> Customer.Blocked::" " then
Error('Customer blocked'); // Hardcoded - avoid this
end;
Rule 3: Code Compilation and Correctness Priority
Intent
Generated AL code should prioritize correctness over immediate compilation. Code can fail to compile if AI suggests base functions or events that don’t exist, or if variables in event subscriptions are incorrect. When this happens, leave space for manual fixes rather than changing the intended behavior. If you’re confident the logic should work as suggested but there are naming or parameter issues, leave it for user correction rather than altering the business logic.
Examples
// Good example - Correct logic even if function names need verification
procedure HandleCustomerModification(var Customer: Record Customer)
var
CustomerValidation: Codeunit "Customer Validation"; // May need verification
begin
// Correct business logic - even if codeunit name needs adjustment
if not CustomerValidation.ValidateCustomerData(Customer) then
Error(ValidationFailedErr);
Customer.Modify(true);
end;
// Good example - Event subscription with correct intent
[EventSubscriber(ObjectType::Table, Database::Customer, OnAfterModifyEvent, '', false, false)]
local procedure OnAfterCustomerModify(var Rec: Record Customer; var xRec: Record Customer; RunTrigger: Boolean)
var
CustomerChangeLog: Codeunit "Customer Change Log"; // Function may need verification
begin
// Correct logic - even if codeunit or method names need adjustment
CustomerChangeLog.LogCustomerChange(Rec, xRec);
end;
Rule 4: Custom Telemetry Implementation
Intent
Add custom telemetry for tracking business-critical operations, but only when explicitly requested by the user. Use Session.LogMessage for custom telemetry with appropriate verbosity levels and data classification. Include relevant custom dimensions for context and use proper telemetry scope for extension publishers.
Examples
// Good example - Custom telemetry (only when user explicitly requests it)
procedure PostSalesDocument(var SalesHeader: Record "Sales Header")
var
TelemetryCustomDimensions: Dictionary of [Text, Text];
SalesDocPostedMsg: Label 'Sales document posted successfully', Locked = true;
SalesDocPostFailedMsg: Label 'Sales document posting failed', Locked = true;
begin
// Add context for telemetry
TelemetryCustomDimensions.Add('DocumentType', Format(SalesHeader."Document Type"));
TelemetryCustomDimensions.Add('CustomerNo', SalesHeader."Sell-to Customer No.");
if TryPostSalesDocument(SalesHeader) then begin
// Log successful operation
Session.LogMessage('SAL001', SalesDocPostedMsg,
Verbosity::Normal, DataClassification::SystemMetadata,
TelemetryScope::ExtensionPublisher, TelemetryCustomDimensions);
end else begin
// Log failed operation with error details
TelemetryCustomDimensions.Add('ErrorText', GetLastErrorText());
Session.LogMessage('SAL002', SalesDocPostFailedMsg,
Verbosity::Error, DataClassification::SystemMetadata,
TelemetryScope::ExtensionPublisher, TelemetryCustomDimensions);
end;
end;
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.