Table data access requires explicit object permissions

Properties
AC0031 Info Design Code Fix Ignore Obsolete

When a codeunit, report, query, or xmlport accesses table data without declaring the required permissions, the runtime relies on the calling user’s direct permissions. This breaks indirect permission scenarios, where a user’s license grants only indirect access to a table (for example, indirect write on ledger entry tables or indirect read on the Sent Emails table). Declaring Permissions = tabledata ... = rimd on the object allows the runtime to grant access through the object, regardless of the user’s direct license assignment.

Example

codeunit 50100 "Post Sales Invoice"
{
    procedure Post()
    var
        SalesHeader: Record "Sales Header";
    begin
        SalesHeader.FindFirst(); // Table data access requires explicit object permissions [AC0031]
    end;
}

Add the Permissions property to the containing object:

codeunit 50100 "Post Sales Invoice"
{
    Permissions = tabledata "Sales Header" = r;

    procedure Post()
    var
        SalesHeader: Record "Sales Header";
    begin
        SalesHeader.FindFirst();
    end;
}

When the diagnostic is reported

The following record method calls trigger this diagnostic:

PermissionMethods
Read (r)Find, FindFirst, FindLast, FindSet, Get, GetBySystemId, IsEmpty, Count
Insert (i)Insert
Modify (m)Modify, ModifyAll, Rename
Delete (d)Delete, DeleteAll

Calls through the implicit Rec variable inside table objects are included (for example, Rec.Modify() in a table procedure).

Report and query dataitem elements require read (r) permissions for their source table.

XmlPort tableelement nodes require permissions based on the Direction property:

DirectionRequired permissions
ImportInsert (i) when AutoSave = true (default), Modify (m) when AutoReplace = true or AutoUpdate = true (defaults)
ExportRead (r)
BothAll of the above

Setting AutoSave, AutoReplace, or AutoUpdate to false suppresses the corresponding requirement.

Exceptions

The diagnostic is suppressed when any of the following conditions apply:

  • The target table is a system table (ID > 2,000,000,000)
  • The codeunit is a test codeunit with TestPermissions = Disabled
  • The containing object is a permissionset or permissionsetextension (these declare permissions structurally, not for access control)

The diagnostic also recognizes multiple permission sources. If any source covers the required operation, no diagnostic is reported.

Object-level Permissions property is the primary source:

codeunit 50100 "My Codeunit"
{
    Permissions = tabledata Customer = r;

    procedure DoSomething()
    var
        Cust: Record Customer;
    begin
        Cust.FindFirst(); // No diagnostic
    end;
}

Table-level InherentPermissions property grants permissions to all callers:

table 50100 "My Table"
{
    InherentPermissions = rimd;
}

Method-level [InherentPermissions] attribute grants permissions for a single procedure:

[InherentPermissions(PermissionObjectType::TableData, Database::Customer, 'r')]
procedure ReadCustomer()

Page SourceTable exemption covers all CRUD on the page’s own source table, including in page extensions. A page that sets SourceTable = Customer does not need to declare permissions for Customer.

Namespace-qualified references (tabledata MyNamespace."My Table" = r) and object ID references (tabledata 50100 = r) are both recognized.

Temporary tables

Temporary tables never touch the database, so they never require permissions. The diagnostic is suppressed for every way a temporary table can be implemented:

  • A record variable marked with the temporary keyword (var Rec: Record Customer temporary;)
  • A table object declared with TableType = Temporary (a plain var Rec: Record MyTempTable; where MyTempTable is a temporary table)
  • A page with SourceTableTemporary = true (covered by the page SourceTable exemption)
  • A report data item or XMLPort table element with UseTemporary = true

Temporary tables don’t require the user to have permissions on the underlying table. Because temporary table data is held only in memory and never read from or written to the database, the permission system doesn’t apply. […] This behavior applies regardless of how the temporary table is implemented—whether by using the TableType property, a temporary record variable, or the SourceTableTemporary property on a page.

Temporary tables on Microsoft Learn

See also