Coming Soon Join the waitlist for 30% off your first year of Folio Docs

Handle Invocable Apex Errors

When something goes wrong, go to Folio Log. Every error raised anywhere in the Folio package lands there automatically, with no wiring on your part. Flow’s fault path carries the same message, but Folio Log is the record that persists and the one to work from.

For the per-action reference, see Automate with Invocable Apex. For chaining recipes and end-to-end scenarios, see Review Invocable Apex Use Cases.

Start with Folio Log

Whenever an error is raised anywhere inside the Folio package — invocable Apex actions, triggers, and editor backend calls alike — Folio writes a record to the Folio Log object automatically. It’s the package’s built-in error trail, and it’s already running.

The log survives a rollback. It’s published as a platform event with PublishImmediately, so it commits outside the transaction. When an action fails and rolls back everything it did, the log record is still there. The error trail exists even when nothing else does.

Folio Log is the first place to look, and the first thing to point Folio Support at when you open a ticket. It carries errors a Flow fault path never sees — failures from the editor, from triggers, and from anything running outside a flow you built. Add the Folio Logs tab to the apps your admins work in so it’s one click away; see Add Folio Docs to the Navigation Bar.

See the data model reference for the key fields and Log retention for how long records are kept.

What happens when an action fails

All 11 actions do the same three things, in order:

1 Write a Folio Log record, which survives the rollback as described above.

2 Raise, with the action label prefixed, so the message names the action that failed.

3 Flow takes the fault path, where you read {!$Flow.FaultMessage}.

Two consequences worth stating plainly

All-or-nothing processing. One bad request fails the entire invocation and rolls back every request in the batch, not just the failing one. A record-triggered flow over 200 records with a single bad ID gets nothing at all. Filtering inputs upstream matters more here than in typical Flow work.

With no fault path, the end user sees the error. This is intentional, so record-triggered before- and after-save flows surface the message on the record page immediately. On a before-save flow it also blocks the save.

Fault path design

The pattern is identical for every action:

  1. Add a Fault Path out of the action.
  2. End the flow on a controlled error path, not a hard failure, so the running user never sees a raw Apex error.

Because the action’s output variables are unavailable on a fault path, {!$Flow.FaultMessage} is the only place the message exists inside Flow.

The fault path doesn’t need to record the error. Folio Log already has it. Assign the fault message to a variable when you want it for a screen message, an email alert, or a downstream decision — not to create an error trail you already have.

If your org’s policy requires errors in a particular system, {!$Flow.FaultMessage} is the value to pass to it, whether that’s RFLIB, a custom log object, or a platform event. That’s a subscriber-org decision rather than something Folio needs.

Common failure categories

FailureLikely causeFix
Fault message names invalid IDsOne or more ID values are blank, malformed, or point to deleted or missing records. Applies to every action, including the Get * actionsTrim empty and null values upstream; the message names every bad value, so fix them all in one pass
[Folio: Share Document] Only public groups (Type = "Regular") are allowed…A Queue, Role, Role-and-Subordinates group, or Customer Portal group was passed as a share targetUse only Public Group IDs. The error names the offending group, its ID, and its type
”User does not have access” / “no rows”Running user lacks sharing or FLS to the targeted DocumentsConfirm the running user has Folio permissions and Document access
”User is inactive” / “missing permission set”A share, transfer, or new-owner target is inactive or lacks the Folio Docs User permission setFilter on IsActive upstream and confirm permission set assignment
”Object not linkable”Record ID for an object not configured as a Linkable ObjectAdd the object under Choose Linkable Objects
”Template / source mismatch”Source record’s object type doesn’t match the template’s configured Source ObjectConfirm template configuration; route the wrong-object branch upstream
Template fails at runtime with no design-time warningThe template is in Draft or Archived statusOnly Active templates can instantiate — see Template Status
Archived Document cannot be modifiedAction targeted a Document that was archived rather than hard deletedUn-archive it first, or filter archived Documents out upstream
Empty result, no errorAll filters were empty, or the running user has no access to matching DocumentsAlways supply at least one filter; consider byOwnerIds or byParentRecordIds

Idempotency and retries

  • Apply Tag to Document, Link Documents to Records, and Share Document are safe to rerun — Folio de-dupes existing Tag links, Junctions, and shares.
  • Refresh Document from Record Changes is safe to rerun; it recomputes from the record’s current state.
  • Transfer Document to Owner is idempotent in that re-running with the same newOwnerId is a no-op.

Delete Document is not safe to retry. Re-running it against a Document that was already actioned raises, either with “The following Document Id(s) could not be found, or the running user does not have access to them…” if it was hard deleted, or “The following Document(s) are archived and cannot be modified: <Title> (<Id>). Un-archive the document(s) before running this action.” if it was archived. That message names every offending Document by title and ID, so you can filter on exactly those rather than guessing which of a batch had already been actioned. Since hard delete is disabled by default, deleting archives the Document — which means a retry in a default org always throws. Build retry logic that filters already-processed Documents out rather than re-running the action blindly.

  • Clone Document and Create Document from Template are not idempotent — every call creates new Documents. Guard against re-firing flow paths with a Decision node (for example, a Has_Handoff_Doc__c flag on the parent record).

Related: Automate with Invocable Apex · Review Invocable Apex Use Cases · Admin Panel Settings · Update Data in Bulk

Continue reading
End User Guide