Use the Page Management codeunit instead of invoking Page.Run directly
When you call Page.Run(Page::"Sales Order", SalesHeader), you hardcode which page opens for a given record. If the record’s "Document Type" is Quote rather than Order, the wrong page opens. The caller is responsible for resolving the correct page variant, and every call site duplicates that logic.
The Page Management codeunit centralizes this resolution. It inspects the record, determines the correct card or list page — including document-type variants like Sales Order vs. Sales Quote — and opens it. It also checks IsGuiAllowed() before running the page, converts record variables to RecordRef automatically, and publishes the OnAfterGetPageID event so other extensions can override page selection without modifying existing code.
Example
The following code hardcodes the page for a Sales Header record:
procedure ShowSalesDocument()
var
SalesHeader: Record "Sales Header"
begin
Page.Run(Page::"Sales Order", SalesHeader); // Use the Page Management codeunit instead of invoking Page.Run directly [AC0006]
endThis opens the Sales Order page regardless of the document type. If SalesHeader is a Quote, the user sees the wrong page.
To fix this, use the Page Management codeunit:
procedure ShowSalesDocument()
var
SalesHeader: Record "Sales Header"
PageManagement: Codeunit "Page Management";
begin
PageManagement.PageRun(SalesHeader);
end;PageManagement.PageRun() resolves the correct page — Sales Order, Sales Quote, Sales Invoice, or Sales Credit Memo — based on the record’s "Document Type" field.
Card vs List pages
Page Management is intended for card pages and worksheet pages (journals). For list pages, use GetDefaultLookupPageIDByVar() to resolve the page ID from the table’s LookupPageId property:
procedure ShowSalesHeaders(var SalesHeader: Record "Sales Header")
var
PageManagement: Codeunit "Page Management";
begin
if SalesHeader.Count() = 1 then
PageManagement.PageRun(SalesHeader)
else
Page.Run(PageManagement.GetDefaultLookupPageIDByVar(SalesHeader), SalesHeader);
end;When the diagnostic is reported
The diagnostic triggers on Page.Run() or Page.RunModal() calls that pass a record of a supported table type. The diagnostic also triggers when Page.Run(0, Record) is used — passing 0 as the page ID defers to the table’s default page, but Page Management provides the same resolution with additional logic and extensibility.
The following tables are supported:
| Id | Name |
|---|---|
| 36 | Sales Header |
| 38 | Purchase Header |
| 79 | Company Information |
| 80 | Gen. Journal Template |
| 81 | Gen. Journal Line |
| 91 | User Setup |
| 98 | General Ledger Setup |
| 112 | Sales Invoice Header |
| 131 | Incoming Documents Setup |
| 207 | Res. Journal Line |
| 210 | Job Journal Line |
| 232 | Gen. Journal Batch |
| 312 | Purchases & Payables Setup |
| 454 | Approval Entry |
| 843 | Cash Flow Setup |
| 1251 | Text-to-Account Mapping |
| 1275 | Doc. Exch. Service Setup |
| 5107 | Sales Header Archive |
| 5109 | Purchase Header Archive |
| 5200 | Employee |
| 5405 | Production Order |
| 5900 | Service Header |
| 5965 | Service Contract Header |
| 7152 | Item Analysis View |
| 2000000120 | User |
Exception
The diagnostic is not raised in the following cases:
No record context:
Page.Run(Page::"Customer Card")without a record parameter. Page Management resolves pages from a record — when there is no record,Page.Runis the correct approach.Capturing the return action: when
Page.RunModal()returns anActionvalue that is used in a condition. Page Management methods returnBoolean, notAction, so this pattern requires the direct call:
procedure SelectCustomer()
var
Customer: Record Customer;
begin
if Page.RunModal(Page::"Customer Lookup", Customer) = Action::LookupOK then
ProcessSelectedCustomer(Customer);
end;- Page declared as a variable: when you declare the page as a variable and call
SetRecord()thenRun(), the page type is already determined at declaration. This pattern is used when you need to call methods on the page instance before running it:
procedure ShowCustomer(var Customer: Record Customer)
var
CustomerCard: Page "Customer Card";
begin
CustomerCard.SetRecord(Customer);
CustomerCard.Run();
end;- Temporary records: Page Management skips temporary records because page resolution is based on table metadata that does not apply to temporary data.
Code fix
The code fix replaces Page.Run and Page.RunModal calls with the corresponding Page Management method:
Page.Run(Page::X, Record)becomesPageManagement.PageRun(Record).Page.RunModal(Page::X, Record)becomesPageManagement.PageRunModal(Record).- When a field parameter is present,
Page.Run(Page::X, Record, FieldNo)becomesPageManagement.PageRunAtField(Record, FieldNo, false)and the modal variant usestruefor the third parameter.
See also
- Codeunit “Page Management” on Microsoft Learn
- Page Management source code on MSDyn365BC.Code.History
- Page.Run() Method on Microsoft Learn
- The Page Management Codeunit by Damiano Zaniboni