Interesting Challenges in Salesforce Troubleshooting

This is a list of troubleshooting/development short stories that I’ve found interesting. They were collected in about a month of consulting done on the Salesforce platform.

Not all of them were developed by me but I’ve been involved in troubleshooting each one. Some of the items are not issues but just reminders (“oh, yes, that works in this way – haven’t seen this one in a while”) and some others are very unusual.

  • Unusual trigger: this one had to properly detect and flag the record when another record with the same grandparent already existed (that is, a “cousin” record), so it leveraged a few extra loops and collections that regular triggers usually don’t need. Normally, Salesforce triggers start with a loop to collect ids and use the collection to retrieve all related records, then proceed to apply some logic with them. This one had a loop to collect parent ids and a query to retrieve parent records, then another loop to collect parent ids of the parent records in order to retrieve the grandchildren of those ids.
  • Bugs only in December: A VisualForce (VF) page was displaying a date in December incorrectly even though the debug logs proved that the variable stored the correct date. Only this week in December was showing incorrectly. Found out that it was using a date format with “YYYY” in uppercase. We need to use “yyyy” in lower case rather than YYYY because YYYY is the year “of the week” rather than the day. Very unusual!
  • Hyper-generic page: created a sales forecasting VF page using only dynamic references to columns. The code only made reference to the SObject name, ID and Name and retrieved records using dynamic SOQL. The rest of the columns were from the fieldsets and the VF page used apex:repeat from a list of field names from the fieldset instead of hard coded. They needed new columns on the VF page and the new columns just had to be added to the fieldset – nice!
  • Encrypted the wrong format: a web service was failing authentication and the error pointed to the encryption. The authentication was done using a variation of JWT (JSON Web Token). We’ve reviewed everything but only got progress troubleshooting when we asked the provider to give us a working example. Then we found out they initially didn’t give us the correct datetime format for the timestamp – it should be yyyy-MM-dd HH:mm:ss instead of yyyyMMdd\’T\’HHmmss.
  • Read-only only for new records: a VF page with checklists was not making fields editable when record was new. If the record already existed, it worked fine and the page prompted the fields for editing as expected. We checked everything and found out that the profile was missing Create permission on the object. Lesson: if a profile is missing Create on the object, the VF page will display the fields as read only if the record is new. That is, fields are not only controlled via field level security. Consequences: one cannot instantiate a dummy object just to expose input fields on the page (and not save it but just copy the values) without having Create permission on the object.
  • Null check everything: that same VF page with checklists for each company was failing when loading existing checklists because one of the companies didn’t have a section of the checklist and the code that populated the checklist was missing a null check for that.
  • Date discrepancy: the VF page with checklists was showing some dates for one user while others saw different dates. Figured out the reason: one of the checklist pages automatically recalculated dates on the screen when loading but left the records intact until the user clicked Save. The other checklist page just showed dates as they were on the database with no recalculation, hence the apparent discrepancy.
  • Quantity stays the same no matter what you type: a VF page “ignored” changes done on the Quantity field when saving. Found out a QuoteLineItem trigger that did some rounding calculation based on packaging and unit of measure (client only sells entire packages measured in kg or lb and not fractions). This trigger was overwriting the Quantity.
  • No cloning without record type: a VF page to clone record with children failed. Found out a query was missing record type id. Oddly, this same page is working in another client org. Needs review to make it even more generic.
  • Boomi licenses: Boomi requires a license per connector per atom (not just per connector) so the same connector used in 2 atoms requires 2 licenses.
  • Folder invisible to Boomi: a network folder containing files to be attached to opportunities in Salesforce was not visible to the connector but it was visible when logged in to the server via TeamViewer. We tried to have the Atom service running as an user to whom the folder had been granted, rather than run as a Local System user. It only worked after copying the files locally instead of a network folder.
  • superficialClone() method: this one is really odd! – a VF page did a deepClone() on a QuoteLineItem in order to store the record as it was originally and compare it later to detect if the user had changed it. After the deepClone() the cloned record changed a decimal field from 9033.60 to 9033.599999999999 which made the comparison fail! Had to use “if( Math.abs( qli.Pre_Discount_Price__c – originalQLI.Pre_Discount_Price__c ) < 0.01 )” to detect when the field was NOT changed by the user.
  • Don’t split guard clauses: Same VF page that detected when an user had changed a record by comparing it with a deep cloned original: it was failing to detect all changes because the guard clause was split in 2 so it was returning too soon seeing the 1st field unchanged without checking the 2nd field.
  • Frozen on copy/paste: Chrome started freezing on Ctrl C/Ctrl V, had to restart Mac. Never seen that glitch before.
  • Give me the banana object but NOT the gorilla object holding the banana and the entire jungle around both: trouble when deploying Rollup Helper to Production – it had to include a required field in Lead, which had nothing to do with the deployment because the Rollup Helper was used with Account. This copy of the Rollup Helper was missing a test class and a custom setting setup and had a bunch of dependencies. We had to include test classes for them all. Reminder to refactor it to leverage custom metadata and reduce dependencies to make deployment/setup easier.
  • Add “before” before the before: a delete trigger for QuoteLineItem to delete orphaned schedules failed test because the trigger declaration was missing “before delete”.
  • Mind the external Ids: a Boomi integration process to upload and attach files to opportunities was not working because the integration ID (used in Upsert) needed a prefix “EUROPE-” that indicated the source of the parent opportunities and prevented duplicates. Added tracked document variables too.
  • Beware of too long nicknames: a community self registration VF page was failing because the user nickname needed to be truncated to 40 characters.
  • D.R.Y. principle: a VF email template was changed but we didn’t see the changes when testing the template because there were 3 places that needed that same change. Figured out a way to replace the repeating parts with a single one.
  • CSS Skyscraper: a community VF page contained a DocuSign embedded signing inside of an Iframe. The Iframe had 2600px height in order to get rid of excessive scrollbars. However this caused a glitch when the user got to DocuSign for the first time. A prompt would not appear in the view because the iframe was too tall. Had to reduce the height and, unfortunately, get one of the scrollbars back.
  • Supporting equality: while encoding a JWT claim in base64, Salesforce appended a single “=” to the result and that caused the RSA encryption to give a different result, making the DocuSign authentication fail during API calls. Added code to remove = at the end (there was code already removing double =, but not single =). Only found this issue when comparing the encrypted result using JWT.IO which is very useful. When dealing with base64 we need to replace +, / with -, _ (because the latter are filename/URL-safe) and remove = (because they’re just padding).
  • Clone the metadata too: a VF page for Cloning record with children wasn’t resetting a certain field because Production was missing a custom metadata record that configured the VF page to set that field to null when cloning.
  • “Y U NO use master-detail?”: a client had an integration that created “User” records in Salesforce (a custom object) from which a trigger needed to create pairs of Account-Contact records and prevent duplicates by assigning users to matching records. The custom object User_c relationship to Account was lookup instead of master-detail. Why? We try to mirror the flow of data: user exists first and there is no account yet, so there isn’t a master yet to justify using master-detail. The expected reply: “But you could create the master account in a before trigger…” Yes, we could but it doesn’t mean we should. Mirroring the flow of data is more prudent. The data volume may grow enough later that you end up having to run the trigger code asynchronously (be done with saving the record to not hinder the integration and run the code to assign Account/Contact pairs later). A master-detail wouldn’t give that flexibility.
  • “When you solve a problem using RegEx, now you have two problems”: a class was doing stringVariable.split( ‘|’ ) to use vertical pipe as a value separator and it didn’t work. It needed to be stringVariable.split( ‘\\|’ ) because this version of split() uses RegEx and the pipe character needs to be escaped once (\|) and the escape character (\) also needs to be escaped (hence \\|).
  • Get the Good GUID: DocuSign API authentication was failing with error “consent_needed”. Found out that the web service call was configured with the organization admin’s user GUID instead of the developer GUID.
  • Community assets for everybody: a community login page was not loading the logo image because the client unchecked the setting that allows guest users to see community assets.
  • Lightning Web Component timing: a component to show account owner picture was not showing the account owner because when it ran the getter function the record hasn’t yet been retrieved. Had to change the flag that indicated that there was an owner picture from a getter function to a @track variable and populate it in the method that retrieved the record. Then found another @track variable reference missing a “this.” prefix.

The biggest benefit of documenting these issues, however small they may be, is the possibility of creating processes and checklists from them to help develop and troubleshoot faster.

Some of the issues can be minimized by following processes. We try to do things in a certain order of steps to avoid forgetting things, which usually happens often because of interruptions.

Say a person is in the middle of developing something but it is time to join a conference call – the context the person had in mind is lost after the call and it is easy to miss some detail from that context.

Checklists may help with troubleshooting too, for example, “when troubleshooting API calls: use JWT.IO to compare the encrypted request, review the credentials one more time, check date formats, etc”.


Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *