Innovative approach to error trapping and handling in FileMaker – Part 2 of 2

In part 1 of this 2-part blog series, we discussed the importance of adopting a defensive approach to programming, one in which we assert conditions in our code, and trap for and handle errors. We also discussed some of the reasons and misconceptions that lead FileMaker developers to not implement thorough error trapping in our applications. Finally, we suggested that error trapping should be second nature and a common practice for every developer.

In this second post, we’ll cover in detail an error-trapping technique that we call “clew”. We have made this technique available free and open source. We have been using it for over 5 years in various client projects, so it’s a proven and “battle-tested” technique.

Why “Clew”

The term clew was coined by Anders Monsen, and it’s a pun on the term “clue” and the name of the game “Clue” or “Cluedo”, as in using the clew technique gives you a clue into what caused an error. Additionally, the term “clew” is an old English term to refer to a ball of yarn, and here the idea is that the clew technique can help us make sense of the complex “ball of yarn” that computer applications can become.

What Clew Is and What It Is Not

Clew is implemented as a set of custom functions that have no dependencies on anything but themselves (it’s fully self-contained). It’s framework agnostic; it does not care about how you pass parameters into scripts, nor how you return results from scripts.

Clew is independent of how errors are logged, how notifications are sent, and how messages are displayed to users (although you may choose to leverage clew to display error messages to users). Clew does not prescribe how to handle errors; it simply gives you the tools to do it.

Finally, clew uses a single variable with local scope (no need for any cleanup of global variables), whose name you can easily specify in the one configuration custom function, which is where you can customize other settings too.

How Clew Works

Single-pass Loop Technique

Clew leverages the single-pass loop construct in FileMaker scripts. The single-pass loop construct is a technique used by FileMaker developers to resemble what in other languages is called a “try” block. It consists of having the code we want executed inside a Loop / End Loop script step block, and forcing the loop to exit after the first iteration (thus the name “single-pass” loop). This allows us to assert conditions, trap for errors, and exit the loop when an error occurs, simply by using Exit Loop If script steps. The pseudo try block in question is typically followed by a pseudo “catch” block. Try-catch blocks are very commonly used in many programming languages, e.g.:

Here is an example of a single-pass loop with a pseudo catch block at the end:

Example of a single-pass loop with a pseudo catch block at the end.

The “If [ error.WasThrown ]” block after the single-pass loop constitutes a pseudo-catch block. It represents a single, central place where we can handle any errors that may have occurred in the pseudo try block. This pseudo try-catch construct eliminates the need to write multiple Show Custom Dialog, Go To Layout (original), Close Window, Exit Script, etc, steps, every time after we trap for an error (see post 1 for an example of such a script). Instead, we can handle any cleanup that needs to happen, displaying a message to users, exiting the script, etc, in a single, central location, i.e., the pseudo catch block. The way this is accomplished is by having the expressions used in the Exit Loop If steps return true if an error occurs. That results in the single-pass loop being exited, and script control is transferred to line 26, where we check if an error occurred (aka “was thrown” – see next section).

Throwing Errors

Clew leverages the single-pass loop construct and builds on it. The two error.Throw functions in the screenshot above, in lines 11 and 13, are two functions that we can use to declare or “throw” an error (“throwing an exception” or “throwing an error” are terms commonly used in programming languages, and for the sake of this post, used interchangeably). The error.Throw functions do the following two things:

  • They exit with true if an error occurs, so that the Exit Loop If step evaluates to true, and thus the pseudo-try block (the single-pass loop) is exited.
  • They set a local variable (whose default name is $clew.ERROR, but which you can easily rename in function error.Config) to an error object.

That error object is implemented as a JSON object, and it looks like this:

{
  "code": "MISSING_REQUIRED_PARAM",
  "description": "Missing a required parameter",
  "hint": "Missing param_two required parameter(s)",
  "script": {
    "name": "Demo script - Terse",
    "parameter": {
      "param_one": 15
    }
  },
  "state": {
    "accountName": "Admin",
    "applicationVersion": "Pro 21.1.1",
    "layoutName": "DemoTable Layout",
    "recordOpenCount": 0
  }
}

This error object captures the name of the script in which the error “was thrown”, i.e., “Demo script – Terse”, the parameters passed to it, i.e., param_one, which had a value of 15, the error code that was generated, in this case custom code “MISSING_REQUIRED_PARAM”, etc. It also contains a “state” property that is completely customizable and in which you can easily capture whatever state or environmental information you want to capture for when a given script was running, to help you troubleshoot your scripts.

Capturing a Trace of Scripts and Errors

One of the main benefits of clew is that it automatically generates a trace of all scripts in the script call stack when an error occurs. By “script call stack,” I am referring to the set of scripts that are being executed at any given point in time in FileMaker, e.g.:

Set of scripts that are being executed at any given point in time in FileMaker

That trace is implemented as a JSON array. Here is a simple example of an error trace generated by clew, which is what’s generated by the script in the first screenshot in this post, when the call to subscript “throws FMP error – Send Mail” in line 18 results in that subscript throwing an error:

{
  "directionOfTrace": "caller_script_last",
  "errorTrace": [
    {
      "code": 1502,
      "description": "Connection refused by SMTP server",
      "hint": "Failed to send notification for monthly reconciliation report",
      "script": {
        "name": "throws FMP error - Send Mail",
        "parameter": null,
        "stepNumber": 7,
        "stepType": "Send Mail"
      },
      "state": {
        "accountName": "Admin",
        "applicationVersion": "Pro 21.1.1",
        "layoutName": "AnotherTable Layout",
        "recordOpenCount": 1
      }
    },
    {
      "code": "UNEXPECTED",
      "description": "Generic, default error",
      "hint": "Unexpected error when calling this subscript: 'throws FMP error - Send Mail'",
      "script": {
        "name": "Demo script - Terse",
        "parameter": {
          "param_one": 15,
          "param_two": "I am a string"
        }
      },
      "state": {
        "accountName": "Admin",
        "applicationVersion": "Pro 21.1.1",
        "layoutName": "DemoTable Layout",
        "recordOpenCount": 0
      }
    }
  ]
}

By using function error.InSubscriptThrow in line 19, after calling the subscript, an element is automatically added to the errorTrace array, to capture the fact that script “Demo script – Terse” called script “throws FMP error – Send Mail”, and that subscript returned an error. In this case, the original error is a FileMaker native error, 1502 (Connection refused by SMTP server). Since it’s a FileMaker error, the clew functions automatically capture the step number in which the error occurred (step number 7 in this case), and the type of step (Send Mail).

Note also the information captured in the state object for each script, i.e., in each array element. In this case, it shows us the layout that each script was executed on, how many open records were in each case (1 when the error in the subscript was generated), etc. This type of information can be very valuable for troubleshooting purposes. Extending what state info is captured by clew is as easy as adding FileMaker Get functions to the error.Config function. You can also add whatever custom expression you want to use, so long as it returns valid JSON. Additionally, you can specify how you want the trace to be ordered, i.e., caller script first or caller script last.

The examples shown here are contrived examples for demo purposes. We have used the clew technique in API integrations that involve parsing massive JSON objects, involving long chains of subscripts, i.e., call stacks with many scripts in them, in which all kinds of JSON parsing, record creation, and record deletion errors can occur. Because of the detailed error trace that clew generates, when an error has occurred, we have always been able to determine what the root cause was, by simply looking at the clew error trace. This has been a big time saver. Manually trying to re-create any one error could easily take an hour or more, as it would involve setting up the right data conditions in the database and in the API vendor’s admin console, then manually stepping through each FileMaker script, until eventually, we identify the source of the problem.

Inspecting Errors and Branching Accordingly

To generate the error trace example above, we used function error.InSubscriptThrow, which automatically adds an element to the error trace if an error occurs in the subscript.

Alternatively, we can inspect the error returned by a subscript and either handle it or “throw” a new error, as explained in this screenshot:

Inspecting the error returned by a subscript

Note that by throwing a new error in line 70, we add a new element to the error trace, which captures specific information about the caller script (the script that called the subscript that returned an error).

Getting Started with Clew

This was a quick intro to clew. There is more to it than I have covered in this blog post. To get started using this technique, I suggest the following:

  • Download the latest clew file from the clew Github repo.
    • The clew FileMaker file contains all the functions you’ll want to import into your solution, plus it contains a template and demo scripts to help you understand the various clew functions.
  • In the clew Github README, review the visual diagram that depicts where in a script the different clew functions are used and how.
  • Watch the presentation on clew at EngageU that I gave in November of 2024.

Conclusion

Implementing robust assertions and error trapping and handling is key to writing applications that behave as expected, and that fail gracefully when unexpected runtime conditions are encountered.

Using a proven error trapping technique like clew allows you to easily add assertions and error trapping to your code, actually saving you time, rather than it representing an extra burden on development and project budget or timeline.

Implementing robust condition assertions and error trapping should come as second nature to developers, and should be part of just about every computer application that we write, as those principles are key to an application being dependable and secure.

If you have any questions or are interested in partnering with our team on your FileMaker application, contact us today.

Leave a Comment

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

Scroll to Top