Severity levels
| 🔴 Critical | Governor limit violations and security issues — fix before deploying |
| 🟡 Warning | Best practice violations — should be addressed |
| 🔵 Info | Code quality suggestions — low urgency, no production risk |
Apex rules
Critical
SOQL query inside a loop
SOQL query inside a loop
Rule ID:
soql-in-loopA SOQL query is being executed inside a for loop. Each iteration of the loop counts as a separate query against Salesforce’s governor limit of 100 SOQL queries per transaction.Why it matters: In production, this will throw a System.LimitException: Too many SOQL queries: 101 error when the loop runs more than 100 times.Fix: Move the SOQL query outside the loop. Collect the IDs you need first, then query with a WHERE Id IN :idSet pattern.DML statement inside a loop
DML statement inside a loop
Rule ID:
dml-in-loopA DML statement (insert, update, delete, upsert, or undelete) is being executed inside a for loop. Each iteration counts against Salesforce’s governor limit of 150 DML statements per transaction.Why it matters: In production, this will throw a System.LimitException: Too many DML statements: 151 error when the loop runs more than 150 times.Fix: Collect records in a list inside the loop, then perform a single bulk DML operation after the loop.@future call inside a loop
@future call inside a loop
Rule ID:
future-in-loopA @future method is being called inside a for loop. Each call counts against Salesforce’s governor limit of 50 future calls per transaction.Why it matters: In production, this will throw a System.LimitException: Too many future calls: 51 error when the loop runs more than 50 times.Fix: Refactor the @future method to accept a collection of IDs and call it once outside the loop.Hardcoded Salesforce record ID
Hardcoded Salesforce record ID
Rule ID:
hardcoded-idA Salesforce record ID is hardcoded directly in the code. Record IDs are org-specific and will be different in every sandbox, scratch org, and production environment.Why it matters: Code with hardcoded IDs will fail silently or throw errors when deployed to a different org. This is a common source of bugs when promoting code from sandbox to production.Fix: Use a Custom Label, Custom Setting, or Custom Metadata Type to store org-specific IDs and reference them in your code instead.Warning
Missing sharing keyword
Missing sharing keyword
Rule ID:
missing-sharing-keywordAn Apex class is declared without an explicit with sharing, without sharing, or inherited sharing keyword.Why it matters: Without an explicit sharing declaration, the class inherits the sharing context of its caller — which may be without sharing. This can expose records the running user should not have access to.Fix: Add an explicit sharing keyword to every Apex class.SOQL mode unspecified
SOQL mode unspecified
Rule ID:
soql-mode-unspecifiedA SOQL query does not explicitly specify USER_MODE or SYSTEM_MODE.Why it matters: Without an explicit mode, SOQL runs in system mode by default — ignoring the running user’s field-level security and object permissions. This can expose data the user should not have access to.Fix: Add WITH USER_MODE to enforce the running user’s permissions, or WITH SYSTEM_MODE to make the intent explicit.Unsafe single-record SOQL
Unsafe single-record SOQL
Rule ID:
unsafe-single-soqlA SOQL query expected to return a single record is assigned directly to a variable without null protection or a try-catch block.Why it matters: If the query returns no records, Salesforce throws a System.QueryException: List has no rows for assignment to SObject error — which will crash the transaction.Fix: Wrap the query in a try-catch block or query into a list and check for results first.Direct trigger logic
Direct trigger logic
Rule ID:
direct-trigger-logicBusiness logic is written directly in the trigger body instead of delegating to a handler class.Why it matters: Triggers with inline logic are difficult to test, maintain, and extend. The Salesforce best practice is to keep trigger bodies thin and delegate all logic to a dedicated handler class.Fix: Create a trigger handler class and call it from the trigger body.This rule has a Low Confidence rating — refactoring trigger logic into a handler class is a structural change that requires careful testing. MoxyCode will explain the pattern but review the suggested fix thoroughly before applying.
Info
System.debug statement left in code
System.debug statement left in code
Rule ID:
apex-system-debugA System.debug() statement is present in the code.Why it matters: Debug statements left in production code clutter debug logs, add minor performance overhead, and can expose sensitive data in logs.Fix: Remove all System.debug() statements before deploying to production.LWC JavaScript rules
Critical
Direct innerHTML assignment
Direct innerHTML assignment
Rule ID:
lwc-inner-htmlA component is using direct innerHTML assignment to render content.Why it matters: Direct innerHTML assignment is an XSS vulnerability — if the content includes user-supplied data, it can be used to inject malicious scripts. Lightning Locker Service also blocks this pattern.Fix: Use LWC template directives (lwc:if, for:each) to render dynamic content safely.@api property mutated directly
@api property mutated directly
Rule ID:
lwc-api-mutatedA component is directly mutating an @api property inside the component.Why it matters: @api properties are owned by the parent component. Mutating them directly breaks the unidirectional data flow pattern in LWC and can cause unpredictable rendering behaviour.Fix: Copy the @api value to a tracked internal property and mutate the internal copy instead.Warning
Direct window access
Direct window access
Rule ID:
lwc-window-accessThe component is accessing the global window object directly.Why it matters: Direct window access is blocked by Lightning Locker Service in production Salesforce orgs. Code that works in local development will fail when deployed.Fix: Use LWC-supported alternatives. For timers, use setTimeout and setInterval without the window. prefix.Direct document access
Direct document access
Rule ID:
lwc-document-accessThe component is using document.querySelector() or similar DOM APIs directly.Why it matters: Direct document access is blocked by Lightning Locker Service. Each component only has access to its own DOM — not the full page document.Fix: Use this.template.querySelector() to access elements within the component’s own shadow DOM.Wire adapter error unchecked
Wire adapter error unchecked
Rule ID:
lwc-wire-error-uncheckedA wire adapter result is being used without checking the .error property first.Why it matters: Wire adapters return both data and error. If the wire call fails and .error is not handled, the component will silently fail or throw a runtime error when trying to access .data.Fix: Always check both .data and .error when using wire adapters.Info
@track decorator on primitive value
@track decorator on primitive value
Rule ID:
lwc-track-unnecessaryA @track decorator is being used on a primitive value (string, number, boolean).Why it matters: Since API version 46, all component properties are reactive by default. Using @track on primitives is unnecessary and adds noise to the code.Fix: Remove the @track decorator from primitive properties.event.target.value used
event.target.value used
Rule ID:
lwc-event-target-valueThe component is using event.target.value to read input values.Why it matters: For Lightning base components (lightning-input, lightning-combobox, etc.), the correct property is event.detail.value. Using event.target.value returns undefined for these components.Fix: Use event.detail.value for Lightning base components.console.log left in code
console.log left in code
Rule ID:
console-log-productionA console.log() or console.error() statement is present in the component JavaScript.Why it matters: Console statements left in production code clutter browser developer tools and can expose sensitive data.Fix: Remove all console.log() and console.error() statements before deploying to production.Imperative Apex call missing .catch()
Imperative Apex call missing .catch()
Rule ID:
lwc-missing-catchAn imperative Apex method call uses .then() without a .catch() block.Why it matters: Without a .catch() handler, any error thrown by the Apex method will be silently swallowed — the component will stop working with no visible error.Fix: Always add a .catch() block to handle errors from imperative Apex calls.LWC HTML rules
Warning
String onclick handler
String onclick handler
Rule ID:
lwc-string-onclickAn onclick attribute is using string function call syntax.Why it matters: String-based event handlers like onclick="handleClick()" are not supported in LWC templates. This is a common mistake for developers coming from Aura components or standard HTML.Fix: Use curly brace expression syntax to reference the handler method.for:each missing key attribute
for:each missing key attribute
Rule ID:
lwc-for-each-no-keyA for:each directive is missing a key attribute on the repeated element.Why it matters: LWC requires a unique key attribute on elements rendered with for:each to efficiently track and re-render list items. Without it, LWC will throw a template rendering error.Fix: Add a key attribute with a unique value — typically the record ID.Shared rules (Apex + LWC)
Warning
Empty catch block
Empty catch block
Rule ID:
empty-catchA catch block is present but empty — exceptions are being silently swallowed.Why it matters: Empty catch blocks hide errors completely. When something goes wrong, there is no log, no user feedback, and no way to diagnose the problem.Fix: Always handle caught exceptions — at minimum, log them or surface an error message.Code Analysis
Learn how MoxyCode surfaces these rules in your editor