Handle errors in your Qlik Sense mashup

While error handling in a Qlik Sense mashup is not automatic, and the documentation is not that good, it’s really not that difficult to get it right. But there are a few things you need to know.

Why do you need it?

Your mashup might work perfectly well when you are testing it. All code is verified, all object id’s refer to objects that actually exist in the app, you have solved the problem with appid’s that differ between your development environment and production. Still there are situations where you need your error handling:

  • unauthorized users: the Qlik Sense hub makes sure to only show apps the user has access to, but for mashups there is no such mechanism, so it’s up to you to handle this situation. Qlik Sense will not allow the user to actually open the app, but he will probably be able to open the mashup, so you will need to handle the situation where he has no access to the app
  • timeout: if your users are inactive, their sessions will be closed. This means that they will not be able to continue (or restart) working in your mashup without reconnecting, most likely by doing a reload of the mashup. You need to tell the user what has happened and what they should do.

Api support

To help you with this is the setOnError method. It allows you to register a function that is called whenever an error occurs. This is both for errors that are the result of a call, like opening an app that does not exist (or the user is not authorized to access), and errors that are generated from the server, like timeouts. Obviously a good start is to display the error.

qlik.setOnError(function (error) {
        // TODO:error handling
        console.log('Qlik error', error);
        $("#errmsg").html(error.message).parent().show();
 });
Or perhaps, a angular version:
//create an array for errors
$scope.errors = [];
qlik.setOnError(function (error) {
    // TODO:error handling
    console.log('Qlik error', error);
    $scope.errors.push(error);
});
and in your template something like this:
<div ng-repeat="err in errors" class="alert">{{err.message}}</div>
Then just add a button for clearing errors ($scope.errors.length = 0 would do the trick) add some styling and you’ve got a first attempt.

Add some intelligence

But for some errors showing the error is not enough. For example if the user gets a timeout, he needs to refresh before continuing to work. If the user has no access the rest of your mashup will probably be empty (well if you show data from other sources they might be available).

To do this we need to use the error code we get with the message. As far as I know there is no official documentation of Qlik Sense error codes, but if you’ve got Qlik Sense desktop installed, you can easily find one. Just start Qlik Sense Desktop and in your browser go to:

http://localhost:4848/resources/translate/en-US/engine.js

As you might have guessed, this file contains, among other things, error code from QIX Engine. After you formatted this file, you will find something like this in it:

"ErrorCode.-128": "Internal engine error",
"ErrorCode.-1": "Unknown error",
"ErrorCode.0": "Unknown error",
"ErrorCode.1": "Some data is not correctly specified.",
"ErrorCode.2": "The resource could not be found.",
"ErrorCode.3": "Resource already exists.",
"ErrorCode.4": "Invalid path",
"ErrorCode.5": "Access is denied",
"ErrorCode.6": "The system is out of memory.",
"ErrorCode.7": "Not initialized",
"ErrorCode.8": "Invalid parameters",
"ErrorCode.9": "Some parameters are empty.",
"ErrorCode.10": "Internal error",
"ErrorCode.11": "Corrupted data",
"ErrorCode.12": "Memory inconsistency",
"ErrorCode.13": "Action was aborted unexpectedly.",
"ErrorCode.14": "Validation cannot be performed at the moment. Please try again later.",
"ErrorCode.15": "Operation aborted",
"ErrorCode.16": "Connection lost. Make sure that Qlik Sense is running properly. If your session has timed out due to inactivity, refresh to continue working.",

So there it is, error code 16 means connection lost, so if we get that we should encourage the user to refresh, perhaps display a button or something and perhaps even disable stuff that won’t work, like selections etc.
The error code from QIX engine will be in error.code in the object that is the parameter to our error funtion, so we can simply test that:

qlik.setOnError(function (error) {
     // TODO:error handling
     console.log('Qlik error', error); 
     $scope.errors.push(error);
     if(error.code === 16){
        $scope.showRefresh = true;
     }
});

Handle proxy errors

But we’re not quite through yet. When you install your mashup on Qlik Sense server, you’ll notice that not all error object have the ‘code’ field. That’s because proxy errors have another format. Instead of the code field, there is a method field. And they’re not in the engine.js file. Instead you need to look in:

http://localhost:4848/resources/translate/en-US/client.js

In it you will find the proxy errors:

"ProxyError.OnEngineWebsocketFailed": "Connection to the Qlik Sense engine failed for unspecified reasons. Refresh your browser or contact your system administrator.",
"ProxyError.OnLicenseAccessDenied": "You cannot access Qlik Sense because you have no access pass.", "ProxyError.OnLicenseAccessDeniedPendingUserSync": "Your access pass credentials are being synced. Refresh your browser or contact your system administrator.",
"ProxyError.OnNoEngineAvailable": "No available Qlik Sense engine was found. Refresh your browser or contact your system administrator.", "ProxyError.OnSessionClosed": "Your session has been closed. Refresh your browser to continue working.",
"ProxyError.OnNoDataPrepServiceAvailable": "Data Profiling service is not available.",
"ProxyError.OnDataPrepServiceWebsocketFailed": "Data Profiling service connection failed. Refresh your browser.",
"ProxyError.OnSessionTimedOut": "Your session has timed out. Log back in to Qlik Sense to continue.",
So there we are, we need to handle also OnSessionClosed and OnSessionTimedOut. This gives us something like this:
qlik.setOnError(function (error) {
     //error handling
     console.log('Qlik error', error);
     $scope.errors.push(error); 
     if(error.code === 16 || ["OnSessionTimedOut","OnSessionClosed"].indexOf(error.method)>-1){ 
        $scope.showRefresh = true;
     }
});
And that’s it, we now have error handling thats shows error messages to users and sets a flag when the user should refresh. We can then use the flag to for example display a refresh button and/or disable interactivity like selections.

Snapshots and Extensions in Qlik Sense

One of the most popular new features in Qlik Sense is snapshots and storytelling. When you discover something interesting in your Qlik Sense app you can take a snapshot of a visualization, including its selections and data, and then build a story where you use it. And you can recreate the selections from the snapshot and drill deeper into your data or look at it from another angle.

In many cases this works automatically for your extension too, but sometimes it doesn’t. In recent versions of Qlik Sense new features, like printing and export to PDF are also built on the snapshot feature, which makes it even more important for it to work. So here is a description of how it works and what you need to do to make your extension work in snapshots.

How does snapshots work?

You create a snapshot by clicking the camera icon in the visualization context menu.  Qlik Sense will then make a copy of the data used for the rendering, known as the layout. This structure is then included in a new bookmark, that is created in Qix engine. Note that it’s not the HTML that is saved, nor is it a bitmap of the actual visualization on the screen. It’s the data.

So when the user wants to look at the snapshot, the data is loaded from the bookmark, Qlik Sense then checks what extension was used to visualize it, loads the extension, creates an object using the visualization, and calls the paint method of the visualization. But the layout parameter will not contain live data from the current selection state, it will contain data from the snapshot.

What this means for your extension

For snapshots to work your extension should use only the layout when rendering.  You should not try to use the capabilities APIs to access data dynamically. Most likely it will not work, and if you manage to get it working, the data you get will be live and not reflect the state when the snapshot was taken. So make sure you add the data you need to the properties structure instead.

Also you need to keep the layout clean. It is good practice to treat it as read-only, adding nice-to-have references make make it impossible to serialize the layout, and creating the snapshot might fail.

And don’t forget to test creating snapshots from your extensions. Also verify that printing and exporting to PDF works, very likely your users expect them to.

New version of Qlik Sense variable extension released

I have just released a new version (3.1) of the Qlik Sense variable extension at GitHub  and Qlik Branch. News in this relaese is that you can have dynamic values for your dropdown list and buttons. It is based on a contribution, but I refactored it somewhat to make it a bit more general and make buttons dynamic too.

It should be totally backward compatible with the previous release and upgrading should not cause you any problems.