[BUG][code-analyzer] sfge: a guard condition on a SOQL result aborts the entry point (TodoException in SchemaBasedValidationAnalyzer)
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 72/100
Research direction
Start with SchemaBasedValidationAnalyzer.java, especially getDerivedApexValue and the ApexSoqlValue path described in the report. Reproduce the sfge command against the supplied SoqlDerivedCondition entry point; done means an uninterpreted condition no longer aborts the entry point and analysis continues without an InternalExecutionError.
Written by the indexing model from the issue text.
Description
Have you tried to resolve this issue yourself first?
- I confirm I have gone through the above steps and still have an issue to report.
Bug Description
Engine: sfge (Salesforce Graph Engine) · Rule: ApexFlsViolation (DevPreview) · Selector: --rule-selector sfge
SchemaBasedValidationAnalyzer.getDerivedApexValue accepts four ApexValue kinds and throws for everything else:
// SchemaBasedValidationAnalyzer.java:85-91
if (!(apexValue instanceof ApexBooleanValue)
&& !(apexValue instanceof ApexCustomValue)
&& !(apexValue instanceof ApexForLoopValue)
&& !(apexValue instanceof ApexSingleValue)) {
throw new TodoException(
"What should I do if ApexValue from StandardCondition is not an ApexBooleanValue, "
+ "ApexCustomValue, ApexForLoopValue, or ApexSingleValue: ApexValue=" ...
ApexSoqlValue reaches it easily: ApexSoqlValue.apply returns Optional.empty() for every method it does not model, so a condition calling an unmodelled method on a SOQL-derived value resolves back to the ApexSoqlValue itself.
The triggering shape is "query with WITH USER_MODE, guard, loop, branch on a field, DML" — the single most common shape in a Lightning controller.
Output / Logs
TodoException: What should I do if ApexValue from StandardCondition is not an ApexBooleanValue,
ApexCustomValue, ApexForLoopValue, or ApexSingleValue: ApexValue=ApexValue(ApexSoqlValue)
{status=INITIALIZED, declarationVertex=null, valueVertex=SoqlExpression{...Query=[ SELECT Id, Title,
FileType, Checksum FROM ContentVersion WHERE Id IN :versionIds WITH USER_MODE ]...}, resolvedValues={},
returnedFrom=null, invocableExpression=null, method=null}, parent=Unknown{conditionType=UNKNOWN, ...},
vertex=MethodCallExpressionVertex{fullMethodName=file.FileType.startsWith, ...}:
com.salesforce.rules.fls.apex.operations.SchemaBasedValidationAnalyzer.getDerivedApexValue(SchemaBasedValidationAnalyzer.java:89);
com.salesforce.rules.fls.apex.operations.SchemaBasedValidationAnalyzer.getDerivedApexValue(SchemaBasedValidationAnalyzer.java:117);
com.salesforce.rules.fls.apex.operations.SchemaBasedValidationAnalyzer.checkForValidation(SchemaBasedValidationAnalyzer.java:74); ...
Steps To Reproduce
- Create an empty SFDX project (
sfdx-project.jsonwith a singleforce-apppackage directory). - Add
force-app/main/default/classes/SoqlDerivedCondition.clswith the class shown below, plus a standardSoqlDerivedCondition.cls-meta.xml(apiVersion 62.0). - Add
code-analyzer.yml:engines: sfge: java_thread_timeout: 900000 java_thread_count: 4 - Run:
sf code-analyzer run --rule-selector sfge --workspace . --config-file code-analyzer.yml - The run reports an
InternalExecutionErrorfor the entry point instead of analysing it. That entry point yields noApexFlsViolationfindings at all, and nothing in the summary indicates coverage was lost.
public with sharing class SoqlDerivedCondition {
@AuraEnabled
public static void run(Set<Id> versionIds) {
List<ContentVersion> fileData = [
SELECT Id, Title, FileType, Checksum
FROM ContentVersion
WHERE Id IN :versionIds
WITH USER_MODE
];
if (fileData == null || fileData.isEmpty()) {
return;
}
List<ContentVersion> out = new List<ContentVersion>();
for (ContentVersion file : fileData) {
String endpoint = 'https://example.com/';
if (file.FileType.startsWith('image')) {
endpoint += 'images';
} else {
endpoint += 'documents';
}
file.Title = endpoint;
out.add(file);
}
update out;
}
}
Expected Behavior
A condition the analyzer cannot interpret is not evidence of anything — it should contribute no schema-based validation and let evaluation continue. The sibling branch twenty lines above already does exactly that:
if (!apexValueOptional.isPresent()) {
// If standard condition does not resolve to an ApexValue, there isn't much we can do
return results;
}
Throwing instead costs the whole entry point's coverage over a condition that was never going to be a sanitizer.
Operating System
macOS 26.5.2
Salesforce CLI Version
@salesforce/cli/2.147.7 darwin-arm64 node-v24.5.0
Code Analyzer Plugin (code-analyzer) Version
code-analyzer 5.15.0
Node Version
v24.5.0
Java Version
openjdk version "11.0.32" 2026-07-21
Python Version
N/A
Additional Context (Screenshots, Files, etc)
5 occurrences across 3 distinct @AuraEnabled entry points in our codebase.
Reported verbatim as #1747 in February 2025 and closed as a duplicate of #1497. #1497 has since been closed too, so there is no longer an open home for it.
Workaround
Hoist the field into a local before the condition (String fileType = file.FileType; then branch on fileType). Fragile — it depends on which method the condition calls.
Urgency
Moderate
- Dominant language
- TypeScript
- Stars
- 240
- Forks
- 52
- Avg merge
- 9h 48m
- Merged PRs (30d)
- 3
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from forcedotcom/code-analyzer
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
forcedotcom/code-analyzer#2094 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
forcedotcom/code-analyzer#2093 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
forcedotcom/code-analyzer#2091 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
forcedotcom/code-analyzer#2090 ·
-
Difficulty 4/5 3-5 days Newbie friendliness 45/100
forcedotcom/code-analyzer#2099 ·
All issues in forcedotcom/code-analyzer
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
ontola/atomic-server#1625 ·
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
melgarafael/DeskcommCRM#1451 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 82/100
-
bug via-triage
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
bot:ai-assisted component:compact-js status:untriaged
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
midnightntwrk/midnight-sdk#403 ·