System.SObjectException: SObject row was retrieved via SOQL without querying the requested field: Account.Phone
What does this error mean?
When Salesforce retrieves records via SOQL, the result set only contains the fields explicitly listed in the SELECT clause. If Apex code later tries to read a field that wasn't queried, Salesforce throws this exception rather than returning null — because a null value could mean either "not queried" or "the field genuinely has no value", and Salesforce enforces clarity on this distinction.
Common Causes
1. Using SELECT Id only then accessing other fields
Querying SELECT Id FROM Account for efficiency, then passing the result to a method that accesses acc.Name, acc.Phone, etc.
2. Fields added to business logic but not to queries
A new feature is added to a trigger handler that reads a new field, but the SOQL query in the trigger wasn't updated to include that field.
3. Relationship field traversal on un-queried relationship
Accessing contact.Account.Name when the query was SELECT Id FROM Contact without querying the parent relationship.
How to Fix It
Solution 1: Add the missing field to SELECT
// ❌ BAD — Phone not in SELECT
Account acc = [SELECT Id FROM Account LIMIT 1];
String phone = acc.Phone; // throws SObjectException
// ✅ GOOD — include all needed fields
Account acc = [SELECT Id, Name, Phone FROM Account LIMIT 1];
String phone = acc.Phone; // safe
Solution 2: Query parent relationship fields explicitly
// ❌ BAD — parent fields not queried
Contact c = [SELECT Id FROM Contact LIMIT 1];
String accName = c.Account.Name; // throws SObjectException
// ✅ GOOD — query through relationship
Contact c = [SELECT Id, Account.Name, Account.Phone FROM Contact LIMIT 1];
String accName = c.Account?.Name; // safe, null-checked
Pro Tip: During development, Salesforce Inspector (browser extension) lets you explore all fields on a record in real-time. This helps you identify exactly which field API names to add to your SELECT clause without switching between Setup and your IDE.