Flow Errors voorkomen en afhandelen

Flow Builder is een fantastische tool waarmee je automatisering in je Salesforce omgeving in elkaar klikt zonder code te hoeven schrijven. Je kunt er met de lessen op Trailhead behoorlijk mee leren werken. Zelfs een paar simpele flows kunnen eindgebruikers uren repetitief klikwerk per week besparen. Het is dus zeker waardevol voor admins om met deze tool te leren werken.

De basis van Flows bouwen is goed en snel te leren, maar fouten maken is ook gemakkelijk. En het is toch een beetje jammer als de gebruikers de helft van de tijd een onafgehandelde fout zien, die hun geen enkele aanwijzing geeft over wat er fout is gegaan. Daarom kijken we in dit artikel naar de mogelijke oorzaken van Flow Errors, hoe je ze kunt voorkomen en hoe je je flow laat omgaan met fouten die je niet kunt voorzien of voorkomen.

O ja, nog één klein dingetje voor we beginnen:

Experimenteer altijd in een sandbox en nooit in de productie omgeving!

Redenen voor foutmeldingen

Niet opgehaalde / beschikbare gegevens

In je flow gebruik je ongetwijfeld regelmatig veldwaarden uit records in opzoekfilters, beslissingen, toewijzingen of een andere bouwsteen van je flow. Maar als die waarde niet is opgehaald of niet bestaat, zal het niet werken.

Bij het debuggen kom je daar vaak snel genoeg achter, maar vaar niet blind op één test met de zogenaamde ‘happy flow’ die je gewoon als jezelf uitvoert. Je test natuurlijk meestal met nette testrecords waarbij de velden en relaties die je nodigt hebt gewoon gevuld zijn, maar in de dagelijkse praktijk is data lang niet altijd zo schoon.

Best Practice 1: Null Checks

Gebruik beslissingen om te controleren of de flow inderdaad het record en de veldwaarden die je nodig hebt, heeft kunnen vinden. Laat de flow alleen de bedoelde route vervolgen als de benodigde data beschikbaar zijn.

Deze beslissing controleert of de Account relatie op de Opportunity gevuld is en of de naam van dit Account gevuld is

Best Practice 2: Automatically store all fields

Als je records ophaalt, kies dan bij How to Store Record Data voor Automatically store all fields. Hierbij maakt de flow zelf de recordvariabele aan en krijg vanzelf je alle velden inclusief de velden van bovenliggende records tot je beschikking. Dit betekent ook dat als je een Opportunity of Contact ophaalt, je het Account en velden op dat Account er gratis bij krijgt en je daarvoor dus niet nog een eigen Get Records element hoeft te gebruiken.

Lees- en schrijfrechten

Zelfs al haalt je flow netjes de records en velden op die je nodig hebt, dan kan het nog voorkomen dat de flow voor jou prima werkt, maar voor andere gebruikers niet. Dit kan aan de leesrechten liggen die het profiel van die gebruiker heeft op het object of het veld. Als je flows bouwt heb je over het algemeen een System Administrator profiel en dat profiel geeft je View All Data en Modify All Data machtigingen. Die machtigingen hebben de gewone stervelingen, als het goed is, niet.

Best Practice 3: Debug as user

Debug daarom je flow ook als een gebruiker die er uiteindelijk mee gaat werken. Gaan er mensen met verschillende profielen en permission sets mee werken. Test dan voor alle verschillende rechtenpakketten. Deze functionaliteit is alleen in sandboxes beschikbaar.

De mogelijkheid om als andere gebruikers te debuggen schakel je in onder Process Automation Settings.

Rechten op objectniveau: profielen of permission sets

Mist een gebruiker bepaalde toegang, dan kun je de rechten om een object te mogen lezen, aanmaken, bewerken of verwijderen beheren op het profiel of in een permission set.

Rechten op veldniveau: Field level security

De toegang op veldniveau kun je niet instellen in een permission set. Dit kun je per veld doen in de Object Manager. Ga naar het juiste object > Field and Relationships, klik het veld aan waarvoor je de toegang wilt bewerken en klik op de knop Set Field-Level Security. Hier kun je per profiel instellen of het veld zichtbaar en leesbaar moet zijn.

Je kunt gebruikers toegang geven om een veld wél binnen een flow te kunnen zien of bewerken, maar het invisible of read-only maken op de Page Layout of Lightning Page voor die gebruiker, zodat ze in de normale weergave geen lees- of bewerkrechten hebben.

Een andere manier kan zijn om de flow in System Context te laten werken. Dit is een optie die je kunt kiezen onder Advanced wanneer je de flow opslaat.

Recordtoegang

Naast toegang tot het object en het veld, speelt ook de toegang op recordniveau een rol. Soms zijn record niet zichtbaar voor alle gebruikers, maar alleen voor de eigenaar. Of ze zijn wel zichtbaar voor iedereen, maar kunnen niet door alle gebruikers bewerkt worden.

Als je tijdens het debuggen merkt dat een gebruiker om die reden vastloopt in de flow, controleer dan of de gebruiker zulke records binnen de flow toch wel moet kunnen zien en/of bewerken of dat deze beperkte toegang correct is.

Wil je binnen de flow een uitzondering maken, dan kun je de flow laten uitvoeren in System Context Without Sharing.

Validaties

Bij het aanmaken of bewerken van een record kun je ook een probleem ondervinden als het record dat je wilt opslaan niet aan validaties voldoet. Met validaties bedoel ik meer dan alleen validatieregels:

  • Een record proberen op te slaan met een verplicht veld niet ingevuld
  • Een record proberen op te slaan met een waarde in een restricted picklist die niet in de lijst met mogelijke opties staat
  • Een record proberen op te slaan die niet voldoet aan een validatieregel

Als je tijdens het debuggen zo’n foutmelding tegenkomt, zie je het duidelijk in de debug log.

Best Practice 4: Picklist Choice sets

Een goede manier om foute picklist values te voorkomen, is om in schermelementen waar de gebruiker zo’n picklist moet invullen niet losse choices te gebruiken, maar een picklist choice set. Die vereist ook geen aanpassing als je ooit keuzelijstwaarden gaat toevoegen, aanpassen of deactiveren.

Gelden er validatieregels voor een bepaald veld, gebruik dan in je flow ook een validatie op het invoerveld. De validatieregel is niet 1 op 1 hetzelfde omdat de velden in de flow net even anders worden geschreven in termen van haakjes en omdat validaties in een Flow Screen Element precies omgekeerd werken als validatieregels in de Object Manager.

Een validatieregel in Object Manager geeft de foutmelding als de formule de uitkomst TRUE heeft en keurt de record goed als de uitkomst van de formule FALSE is.

Hier beschrijf je dus wanneer de invoer fout is

Een validatieregel in een Screen Component in je flow keurt de invoer juist goed als de uitkomst van de formule TRUE is en geeft de foutemelding wanneer de uitkomst FALSE is.

Hier beschrijf je dus wanneer de invoer juist is.

Een validatieregel in Object Manager geeft een foutmelding als de uitkomst van de formule true is
Een validatieregel in een Screen Component in je flow keurt de invoer goed als de uitkomst van de formule true is

In het bovenstaande voorbeeld zie je twee verschillen. In de Object Manager gebruik je gewoon de veld API naam (in dit geval Phone). In Flow Builder staat de API naam van het input component tussen accolades met een extra uitroepteken vooraan: {!Phone}.

Niet alle typen invoervelden in Flow Screen Components hebben de mogelijkheid op de input te valideren. Een Phone component heeft dit niet en ook al definieer je in de component als in welk veld de invoer wordt opgeslagen, de validatieregels die gelden op dat veld worden niet binnen de flow gecheckt.

Gebruik je in je screen Dynamic Forms om de velden van een record variabele zelf er direct in te zetten, dan worden de validatieregels zoals in de Object Manager gedefinieerd wel gecheckt voor het veld in kwestie.

Gebruik daarom voor de invoer van velden waar validatieregels op van toepassing zijn normale tekst en getal componenten

Limieten

Flow Builder is onderhevig aan limieten. Over die limieten heen gaan, resulteert ook in foutmeldingen. Met welke limieten je allemaal rekening moet houden, vind je hier:

https://help.salesforce.com/s/articleView?id=sf.flow_considerations.htm&type=5

De voornaamste twee waar je rekening mee moeten houden tijdens het bouwen van je flow zijn:

  • Maximaal 100 SOQL queries (data ophalen uit de database)
  • Maximaal 150 DML statements (data bewerken in de database, Create, Update of Delete Records)

Beide gelden per Flow Transaction.

Wat is een Flow Transaction?

Een Flow Transaction is alles wat gebeurt tussen:

  • Screenflow:
    • Het starten van de flow en het tonen van een scherm aan de gebruiker
    • Tussen twee opvolgende schermen
    • Van het laatste scherm tot het einde van het Flow Interview
  • Record Triggered en Autolaunched Flows:
    • De trigger die een initiële recordupdate in werking zet plus alle acties die daardoor getriggerd worden en de acties die vervolgens weer door díe wijzigingen worden veroorzaakt tot er geen nieuwe acties meer aan die oorzaak – gevolg – oorzaak – gevolg keten worden toegevoegd.

Dit betekent dat de transactie al begonnen kan zijn voor jouw flow begint en ook door kan lopen na de acties in jouw flow.

Verdiep je dus in hoe wijzigingen waarop jou (Record Triggered) Flow reageert kunnen ontstaan en welke andere Flow en Processen er vervolgens op de wijzigingen reageren die jouw Flow veroorzaakt.

Om dit beheersbaar te maken kan het helpen om daar waar mogelijk record triggered flows asynchroon te laten lopen en Flow Trigger Explorer te gebruiken om de verschillende flows op een handige volgorde te zetten.

Wat is een Flow Interview?

Een Flow Interview is alles wat er vanaf het start element tot het eind element in de flow gebeurt. Dat hoeft niet voor elk interview van dezelfde flow evenveel te zijn. Door beslissingen en hun vervolgpaden kunnen de ene keer veel meer elementen aangetikt worden dan een andere keer.

In loops telt een element in de loop (inclusief het loop element zelf) elke keer dat het opnieuw bezocht wordt weer opnieuw mee. Ook daar heeft het aantal records in de loop dus invloed op hoeveel elementen er in totaal geraakt worden in de flow.

Weliswaar bestaat de limiet van maximaal 2.000 geraakte elementen in een Flow Interview niet meer, maar een tijdsbeperking van maximaal 10 seconden geldt nog wel. Hierom is het goed om te waarborgen dat de delen van een Flow die lopen zonder gebruikersinteractie niet langer duren dan dat. Dit kun je doen door het aantal records dat maximaal in één interview door de loop mag te beperken.

Op loops in flows zal ik in een ander artikel nog eens uitgebreid ingaan.

Maatregelen om de limieten niet te raken

  • Gebruik niet meer Get Record elementen dan strikt noodzakelijk is
    • Zoals aan het begin van het artikel al genoemd, krijg je de velden van bovenliggende records automatisch al mee.
    • Gebruik recordvariabelen als inputvariabelen voor subflows in plaats van alleen de Id’s. Vaak heeft de bovenliggende flow de recordvariabele die je nodig hebt al volledig tot zijn beschikking. Die geef je dan gewoon door aan de subflow.
  • Gebruik nooit een loop binnen een loop (zonder te filteren)
    • Dan gaat de hoeveelheid iteraties van de loop exponentieel omhoog en dan kunnen die 10 seconden soms voorbij zijn voor het Flow Interview klaar is.
    • Heb je wel een dubbele loop nodig, gebruik dan een Collection Filter element tussen het buitenste en binnenste loop element. Laat het binnenste loop element met de gefilterde collectie werken. Zo zal de binnenste loop, als je goed filtert, alleen uitgevoerd worden voor de records die relevant zijn voor de huidige record van de buitenste loop.
    • Als er echt geen andere mogelijkheid lijkt te zijn, schakel dan een developer in om een oplossing in Apex voor je te bouwen. Vaak hoeft dat niet het gehele proces van begin tot eind te zijn, maar kun je een deel isoleren dat met Flow Builder niet haalbaar is. Als de betreffende method in Apex ‘invocable’ wordt gemaakt, kun je deze binnen je flow gebruiken net zoals je een subflow erin zou opnemen.
  • Gebruikt nooit een Get, Create, Update of Delete element binnen een loop
    • Voeg in plaats daarvan de enkele recordvariabele toe aan een record collection variabele en update na het einde van de loop de hele record collection in één Create, Update of Delete element
    • Overleg voor scenario’s waar het lijkt dat je een Get records binnen een loop nodig hebt met een ervaren admin, consultant of developer. Mogelijk heb je een stukje code nodig dat je als een Actie in de Flow kunt opnemen, maar misschien kan je ervaren collega het ook anders oplossen.
  • Filter zorgvuldig wanneer je een Record Update element gebruikt.
    • Als er eigenlijk helemaal geen wijzigingen aan het record hebben plaatsgevonden, voer de update dan niet uit.
    • Dit kun je doen door een beslissing die checkt of een van de Assignments waar waarden van de al of niet te updaten records worden ingesteld geraakt is. Zo ja, dan kun je updaten. Is er geen enkele Assignment bezocht die waarden instelt voor het record, dan is updaten niet nodig.
Alleen als ten minste één van de Assignments bezocht is die een veldwaarde verandert, is het uitvoeren van een update nodig

Foutpaden

Misschien kun je niet alle mogelijke problemen vooraf voorzien. Je weet niet wat je niet weet. Dus het is altijd goed om foutpaden te gebruiken, opdat, als de gebruiker toch tegen een error aanloopt, het niet alleen maar een vage ‘unhandled fault’ is.

Vanaf alle roze elementen met database interactie en alle acties kun je foutpaden trekken.

Daar kun je bijvoorbeeld:

  • De gebruiker een scherm laten zien dat meer informatie over het probleem geeft
  • Het foutrapport delen met andere gebruikers zoals jezelf of een externe consultant
    • opslaan in een custom object record
    • via een custom notification
    • via chatter
    • via email
  • Een rollback uitvoeren die alle wijzigingen aan record die in het flow interview zijn gedaan, ongedaan maakt.

Je kunt de foutafhandeling ook onderbrengen in een subflow die je vanuit elke flow kunt aanroepen. Je kunt dan kiezen om een versie met een scherm te maken voor in Screen Flows en een versie zonder schermen als subflow voor niet-screenflows.

Het voordeel van een Fault log opslaan in een custom object record is dat je het binnen de org kunt terugvinden en het bijvoorbeeld aan een case kunt koppelen waarmee je kunt bijhouden of de oorzaak is opgelost.

Onderstaande flow is slechts en voorbeeld. Hierin wordt het foutrapport vastgelegd in een record van het custom object “System Log”. Vervolgens krijgt de gebruiker niet de hele debug log intergraal te zien, maar wordt het System Log nummer gedeeld in een scherm met het verzoek bij het melden van het probleem dit nummer aan de Admin te door te geven.

Het foutrapport, dat wat jij in feite te zien krijgt bij het debuggen, is in de flow beschikbaar als de variabele: {!$Flow.FaultMessage}.

Je kunt zelf het beste beoordelen welke manier van Errors vastleggen en communiceren voor jou en je gebruikers het beste werkt.

Foutpaden in flows kunnen alleen vanuit roze blokken en Actions gemaakt worden.

Een fout kan ook optreden in een assignment, decision, scherm, record sort of collection filter element en kan ook binnen een formule of text template in de flow zitten. Daar zijn geen foutpaden aan te verbinden, dus op die plekken moet je de fouten er echt van tevoren uit halen door goed te debuggen.

Hopelijk helpen deze tips je om goed werkende flows te bouwen en problemen die er dan toch in optreden sneller te analyseren en op te lossen.