---
schema_version: "1"
id: a2d843a3fa19aecaee1b69098c00447d86a5085a8eb8aa7e2482404fa4122ff4
title: Salesforce Graph Engine Rules Reference
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/code-analyzer/salesforce-code-analyzer/guides/rules-sfge.md
canonical_url: https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/rules-sfge.html
source_site: developer.salesforce.com
content_type: documentation
content_hash: b8516462f6c8150df429bd7c2434d69812eeae9bdbb1ca814ad32ac747d3a0a2
products:
  - Salesforce Code Analyzer
---
# Salesforce Graph Engine Rules Reference

To select the Salesforce Graph Engine rules, use `--rule-selector sfge`. For example, this command runs all the Graph engine rules:

```bash
sf code-analyzer run --rule-selector sfge
```

## ApexFlsViolation

ApexFlsViolation detects Create, Read, Update, and Delete and Field-Level Security (CRUD/FLS) violations.

### Definition

- Entry Point

  - `@AuraEnabled`-annotated methods.
  - `@InvocableMethod`-annotated methods.
  - `@NamespaceAccessible`-annotated methods.
  - `@RemoteAction`-annotated methods.
  - Any method returning a `PageReference` object.
  - `public`-scoped methods on Visualforce Controllers.
  - `global`-scoped methods on any class.
  - `Messaging.InboundEmailResult handleInboundEmail()` methods on implementations of `Messaging.InboundEmailHandler`.
  - Any method targeted during invocation.

- Sink

  - All DML operations and their `Database.method()` counterparts: delete, insert, merge, undelete, update, and upsert.
  - SOQL queries and Database.query counterpart.

- Sanitizer

  - Access check performed using [Schema.DescribeSObjectResult](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_methods_system_sobject_describe.htm).
  - Acceptable only for operations that require CRUD-level checks such as DELETE, UNDELETE, and MERGE.
  - Access check performed using [Schema.DescribeFieldResult](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_methods_system_fields_describe.htm).
  - Acceptable for operations that require FLS-level checks. Includes READ, INSERT, UPDATE, UPSERT for standard data objects and custom objects.
  - Lists filtered by [Security.stripInaccessible](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_with_security_stripInaccessible.htm).
  - SOQL queries that use [WITH USER_MODE](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_enforce_usermode.htm).
  - SOQL queries that use [WITH SECURITY_ENFORCED](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_with_security_enforced.htm#apex_classes_with_security_enforced).

### Interpreting Results

Match any violation message that you receive with these cases to understand more about the violation.

#### Common Case

> _Validation-Type_–validation is missing for _Operation-Name_ operation on _Object-Type_ with fields _Comma-Separated-Fields_

where:

- _Validation-Type_ : Type of validation to be added. CRUD requires object-level checks, and FLS requires field-level checks.
- _Operation-Name_ : Data operation that must be sanitized.
- _Object-Type_ : Object on which the data operations happen. If Graph Engine couldn’t guess the object type, you see the variable name or _SFGE_Unresolved_Argument_.
- _Comma-Separated-Fields_ : Fields on which the data operation works. If you see _Unknown_ as the only field or as one of the fields, Graph Engine doesn't have enough information to guess the fields, and you must determine the unlisted fields manually.

#### Additional Clause Case

> _Validation-Type_ validation is missing for _Operation-Name_ operation on _Object-Type_ with fields _Comma-Separated-Fields_–Graph Engine couldn't parse all objects and fields correctly. Manually confirm if the objects and fields involved in these segments have FLS checks: _Unknown-Segments_

where:

- _Validation-Type_ : Type of validation to be added. CRUD requires object-level checks, and FLS requires field-level checks.
- _Operation-Name_ : Data operation that must be sanitized.
- _Object-Type_ : Object on which the data operations happen. If Graph Engine couldn’t guess the object type, you see the variable name or _SFGE_Unresolved_Argument_.
- _Comma-Separated-Fields_ : Fields on which the data operation works. If you see _Unknown_ as the only field or as one of the fields, Graph Engine doesn't have enough information to guess the fields, and you must determine the unlisted fields manually.

This case is the same as the common case, but also Graph Engine isn't confident about the object names or field names that it detected. You also see this clause when your field or object ends with `__r`. In both cases, review the relational field, object, and the unparsed segments to ensure that they have the required CRUD/FLS checks. Next, add an [engine directive](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-sfge-work-with.md#add-engine-directives) to force Graph Engine to ignore this warning in the next run.

### See Also

- [_YouTube_: Create, Read, Update, and Delete (CRUD) and Field-Level Security (FLS) Violations](https://www.youtube.com/watch?v=1ZYjpjPTIn8)
- [_Apex Developer Guide_: Enforce User Mode for Database Operations](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_enforce_usermode.htm)
- [_Apex Developer Guide_: Enforce Security With the stripInaccessible Method](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_with_security_stripInaccessible.htm)
- [_Apex Developer Guide_: Enforcing Object and Field Permissions](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_perms_enforcing.htm)

## ApexNullPointerException

ApexNullPointerException identifies Apex operations that dereference null objects and throw NullPointerExceptions. NullPointerExceptions generally indicate underlying problems in your code to address.

### Definition

- Entry Point

  - `@AuraEnabled`-annotated methods.
  - `@InvocableMethod`-annotated methods.
  - `@NamespaceAccessible`-annotated methods.
  - `@RemoteAction`-annotated methods.
  - Any method returning a `PageReference` object.
  - `public`-scoped methods on Visualforce Controllers.
  - `global`-scoped methods on any class.
  - `Messaging.InboundEmailResult handleInboundEmail()` methods on implementations of `Messaging.InboundEmailHandler`.
  - Any method targeted during invocation.

- Sink

  - Any object dereference is a potential sink because object dereferences are the places where a null pointer exception can be thrown. Example: `x.someMethod() `.

- Sanitizer

  - Non-null initialization of variables and null checks before accessing. Examples: `String s = 'abcde';` , `if (s != null) {`.

### Interpreting Results

Match any violation message that you receive with this case to understand more about the violation.

#### Common Case

> ApexNullPointerException identifies Apex operations with a high likelihood of throwing a NullPointerException

The operation dereferences a null object and throws a `NullPointerException`. Review your code and add a null check.

### Examples

In these examples, Apex Runtime throws a `System.NullPointerException` at the place where an operation is performed on a null object. The Graph Engine ApexNullPointerException rule preemptively identifies these operations.

```
public void example1() {
	Object myStr = null;
	System.debug(myStr.toLowerCase());
// throws System.NullPointerException
// since method is invoked on null object.
}

public void example2(String myStr) {
	if (myStr == null) {
		// The following line throws System.NullPointerException, since the conditional confirms
		// that myStr is null when it reaches here.
		System.debug(myStr.toLowerCase());
	}
}

public void example3() {
	Integer i; // Not initialized
	Integer y = i + 2;
// throws System.NullPointerException since
// binary operation is invoked on null object
}
```

To fix `NullPointerException` issues, use one of these methods.

- Check that the object is `not-null` before performing the operation.
- Make sure that all variables are initialized.

Avoid initializing variables to `null`. If your logic demands initialization to `null`, make sure to reassign a value to your variable before you invoke an operation on it.

## AvoidDatabaseOperationInLoop

AvoidDatabaseOperationInLoop detects database operations that occur inside loops and that cause performance degradation. Database operations within loops cause performance degradations and exceed Salesforce governor limits.

### Definition

- Entry Point

  - `@AuraEnabled`-annotated methods.
  - `@InvocableMethod`-annotated methods.
  - `@NamespaceAccessible`-annotated methods.
  - `@RemoteAction`-annotated methods.
  - Any method returning a `PageReference` object.
  - `public`-scoped methods on Visualforce Controllers.
  - `global`-scoped methods on any class.
  - `Messaging.InboundEmailResult handleInboundEmail()` methods on implementations of `Messaging.InboundEmailHandler`.
  - Any method targeted during invocation.

- Sink

  - Any database operation.

### Interpreting Results

Match any violation message that you receive with this case to understand more about the violation.

#### Loop Case

> A database operation occurred inside a loop.` [%s at %s:%d]`

Your code executes a database operation inside a loop statement. To move the database operation outside the loop, modify and then rescan your code.

### Best Practices

To remediate database operation violations, move these operations outside of loops. Follow these best practices.

- Instead of querying objects within a loop, use a SOQL `for` loop to iterate over a query’s results.

  For example, instead of:

  ```
  for (String name : names) {
     Account[] accs = [SELECT Name FROM Account WHERE Name =: name];
  ```

  Use:

  ```
  for (Account[] accs : [SELECT Name FROM Account WHERE Name IN :names]) {
  ```

- Instead of putting database operations within a loop, use the loop to iteratively construct lists of objects, and then perform the database operation on the full list after the loop.

  For example, instead of:

  ```
  for (String n : names) {
     insert new Account(Name = n);
  ```

  Use:

  ```
  Account[] accs = new List<Account>();
  for (String n : names) {
     accs.add(new Account(Name = n));
  }
  insert accs;
  ```

## AvoidMultipleMassSchemaLookups

AvoidMultipleMassSchemaLookups is a path-based rule that detects scenarios where expensive schema lookups are made more than one time in a path and cause performance degradation.

AvoidMultipleMassSchemaLookups identifies these methods:

- `Schema.getGlobalDescribe()`
- `Schema.describeSObjects(...)`

Flagged lookups include:

- Lookups within these types of loops: `ForLoopStatement`, `ForEachLoopStatement`, `DoWhileStatement`, and `WhileLoopStatement`
- Multiple expensive schema lookups that are invoked
- An expensive schema lookup that is executed multiple times

These common scenarios trigger a violation from AvoidMultipleMassSchemaLookups.

- `Schema.getGlobalDescribe()` within a loop
- `Schema.describeSObjects(...)` within a loop
- `Schema.getGlobalDescribe()` preceding a `Schema.getGlobalDescribe()` or `Schema.describeSObjects(...)` method call anywhere in the path
- `Schema.describeSObjects(...)` preceding a `Schema.describeSObjects(...)` or `Schema.getGlobalDescribe()` method call anywhere in the path

### Definition

- Entry Point

  - `@AuraEnabled`-annotated methods.
  - `@InvocableMethod`-annotated methods.
  - `@NamespaceAccessible`-annotated methods.
  - `@RemoteAction`-annotated methods.
  - Any method returning a `PageReference` object.
  - `public`-scoped methods on Visualforce Controllers.
  - `global`-scoped methods on any class.
  - `Messaging.InboundEmailResult handleInboundEmail()` methods on implementations of `Messaging.InboundEmailHandler`.
  - Any method targeted during invocation.

- Sink

  - `Schema.getGlobalDescribe()`.
  - `Schema.describeSObjects(...)`.

### Interpreting Results

Match any violation message that you receive with these cases to understand more about the violation.

#### Loop Case

> `Schema.getGlobalDescribe` was called inside a loop. `[ForEachStatement at AuraEnabledFls:27]`

Your code calls `Schema.getGlobalDescribe()` or `Schema.describeSObjects(...)` inside a loop statement. To move the `Schema.getGlobalDescribe()` or `Schema.describeSObjects(...)` outside the loop, modify and then rescan your code.

#### Multiple Schema Lookups Are Invoked Case

> Multiple expensive schema lookups are invoked. `[Schema.describeSObjects at AuraEnabledFls:27]`

Your code invokes `Schema.getGlobalDescribe()` preceded by `Schema.describeSObjects`. Modify your code so that only one expensive schema lookup is invoked.

#### More Than One Execution in a Path Case

> `Schema.getGlobalDescribe` executed multiple times in the call stack. `[getFields at AuraEnabledFls:27, getFields at AuraEnabledFls:28, getFields at AuraEnabledFls:29]`

`Schema.getGlobalDescribe` or `Schema.describeSObjects` is executed multiple times in a single path. Reduce the execution of the method to one time, then rescan your code

## DatabaseOperationsMustUseWithSharing

The DatabaseOperationsMustUseWithSharing rule identifies database operations in classes annotated as `without sharing`. It also warns of database operations in classes that inherit with sharing implicitly instead of explicitly using `inherited sharing`.

With Salesforce sharing rules, you can control who has access to which records, but it's your responsibility to ensure that your Apex code respects sharing rules by declaring classes with a `sharing` model.

- `with sharing` causes database transactions in a class to respect sharing rules. It's the default recommendation.
- `without sharing` causes database transactions in a class to ignore sharing rules. Use with caution.
- `inherited sharing` causes database transactions in a class to inherit the sharing model of the class that called it. Use for classes that require flexibility.

To protect user data in Apex, use `with sharing` or `inherited sharing` whenever possible.

### Definition

- Entry Point

  - `@AuraEnabled`-annotated methods.
  - `@InvocableMethod`-annotated methods.
  - `@NamespaceAccessible`-annotated methods.
  - `@RemoteAction`-annotated methods.
  - Any method returning a `PageReference` object.
  - `public`-scoped methods on Visualforce Controllers.
  - `global`-scoped methods on any class.
  - `Messaging.InboundEmailResult handleInboundEmail()` methods on implementations of `Messaging.InboundEmailHandler`.
  - Any method targeted during invocation.

- Sink

  - Any database operation.

- Sanitizer

  - Class-level with sharing or inherited sharing annotation.

### Interpreting Results

Match any violation message that you receive with these cases to understand more about the violation.

#### Common Case: Error Message

> Database operation must be executed from a class that enforces sharing rules.

The database operation occurs in a `without sharing` context, either because it occurs in a class annotated `without sharing` or because its class inherits sharing from a `without sharing` class. To resolve this violation, add `with sharing` or `inherited sharing` to the class.

#### Common Case: Warning Message

> The database operation’s class implicitly inherits a sharing model from %s %s. Explicitly assign a sharing model instead.

This warning is thrown when a database operation occurs in a class that has no explicitly declared sharing model, so it implicitly inherits `with sharing` from its calling class. Even though the operation is secure in this specific case, it isn’t secure by default. Explicitly assign this class a sharing model to make it secure by default.

## MissingNullCheckOnSoqlVariable

MissingNullCheckOnSoqlVariable identifies SOQL queries with variables in WHERE clauses that lack null checks.
SOQL queries with variables on WHERE clauses become expensive when the variable value is unintentionally null. When the variable value is null, an O(1) operation turns into an O(n) operation. The entire table is scanned but returns no results.

### Definition

- Entry Point

  - `@AuraEnabled`-annotated methods.
  - `@InvocableMethod`-annotated methods.
  - `@NamespaceAccessible`-annotated methods.
  - `@RemoteAction`-annotated methods.
  - Any method returning a `PageReference` object.
  - `public`-scoped methods on Visualforce Controllers.
  - `global`-scoped methods on any class.
  - `Messaging.InboundEmailResult handleInboundEmail()` methods on implementations of `Messaging.InboundEmailHandler`.
  - Any method targeted during invocation.

- Sink

  - Any database operation.

- Sanitizer

  - Null checks (`if (x != null) {`).
  - Explicit assignment to non-null (`String x = 'asdf'`).
  - Checks for specific non-null values (`if (x == 7) {`).

### Interpreting Results

Match any violation message that you receive with this case to understand more about the violation.

#### Common Case

> Null check is missing for variable targetName used in SOQL query.

The mentioned variable is referenced by a SOQL query, and the variable is missing a null check. This behavior is expensive. Instead, explicitly perform a null check on this variable, or assign it to a specific non-null value. For example:

```apex
public Account[] getAccountsMatchingName(String targetName) {
	return [SELECT Id, Name FROM Account WHERE Name := targetName];
}
```

## UnimplementedType

UnimplementedType detects abstract classes and interfaces that are non-global and missing implementations or extensions.

### Definition

UnimplementedType is a traditional static analysis rule where a violation occurs at a point in the code where the interface or abstract class is declared. It doesn’t use sources or sinks.

### Interpreting Results

Match any violation message that you receive with this case to understand more about the violation.

#### Common Case

> Extend, implement, or delete %s %s

Because this abstract class or interface has no implementations or extensions, it can’t be instantiated. It’s unnecessary and can be deleted.

### Limitations

Because the UnimplementedType rule excludes `global` scoped classes from consideration, these classes are prevented from being thrown as false positives and aren’t false negatives.
