In this page


The Better PDF Exporter app records its internal activities to a so-called log. The log helps you to understand the activity of the app when diagnosing problems.

Viewing the log

The Better PDF Exporter app writes its log lines to a secure cloud-hosted log. It can be viewed through the app's user interface:

  1. Go to AppsBetter PDF ExporterView Log.
  2. If you can't see any log line written by the app, wait a few seconds then click "Refresh" and see if it solves the problem.

If you can't interpret the log lines you found, report it to our support. We are there to help you!


This section gives you practical hints to find the root cause when investigating problems in PDF templates and Groovy scripts.

Reduce data

If you see a problem that occurs when exporting a large data set, it is hard to find the precise root cause because of the sheer volume of data. Does it occur for every issue, for Story-type issues only or for the issue FOO-123 only? Similarly, does it occur for every field, for date-type fields only or for the "Due date" field only?

The following techniques help you re-produce a problem with a smaller scope, what is key to find the solution.

Reduce issues

It is helpful when the problem is related to one or more specific issues.

It's a simple idea that you can apply in several ways:

  • If you fail to export a large number of issues, export only the first one! If it fails as well, then you have a single issue to reproduce the problem. To verify if the problem appears for any issue, repeat the test using a few other randomly chosen issues.
  • Or, if you see the problem with a smaller number of issues, start removing issues one by one (or in small batches) and repeat the test after each removal. If the problem disappears, then it is caused by the most recently removed issue (batch).
  • Or, the previous technique in reverse direction: start adding issues one by one (or in small batches) and repeat the test after each addition. If the problem appears, then it is caused by the most recently added issue (batch).
  • Or, find a single or small number of problematic issues in a large dataset with "bisection":
    1. Split up the issues to two similarly-sized partitions (using JQL, for example).
    2. Test with the first partition.
    3. Test with the second partition.
    4. If the problem appears only with one of the partitions, then split that partition again, test those two halves again, and so on.
    5. Repeat this until you have a small scope.

These can be used in combination, be creative!

Reduce fields

It is helpful when the problem is related to a specific field.

The idea is the same as reducing the number of issues, but with fields. Basically, you just systematically add or remove fields and repeat the test until you reach a small scope that reproduces the problem. (You can add or remove fields to the PDF export typically by commenting in and commenting out fields in the template or by adding and removing columns in the Issue Navigator.)

Reduce features

It is helpful when the problem is related to a specific feature (e.g. exporting comments).

Obviously, disable the suspicious feature and test. If the problem disappears, then it is caused by that feature.

Reduce code

It is helpful when the problem is related to a specific code part in the PDF template or in the Groovy script.

Comment out the code part and test. If the problem disappears, then it is caused by that code part.

Other troubleshooting techniques

Advanced techniques in this section can give further help find problems in Groovy code.

Using getter-based expressions instead of property-based ones

Although these are identical when they succeed, the template expression that uses the getter method name may show more details about a problem than its property name based equivalent. Therefore, if you have a problem in the method that calculates the value "baz", replace ${fooBar.baz} with ${fooBar.getBaz()}.

Wrapping problematic code in a try-catch block

When you have a problematic code block, used through a template expression like ${fooBar.getBaz()} or ${fooBar.baz} and it mysteriously breaks the export, wrap it in a try-catch block!

See this example (that deliberately throws an exception to demonstrate "problematic code"):

fooBar = new FooBarTool(logger: logger)

class FooBarTool {
	def logger

	def getBaz() {
		try {
			throw new NullPointerException() // <- this is here just to demonstrate the technique

			// ... problematic code comes here

		} catch (Exception ex) {
			return ex.message

Why does it help in troubleshooting?

  1. The exception will be caught, but the export will not stop!
  2. The exception will be written to the log.
  3. The exception message will be returned to the template. It will appear exactly where the actual value should, giving you a "very visual" way of locating the problem.

Typical problems and their solutions

Groovy-related problems

I get MissingPropertyException or MissingMethodException in a Groovy script.

These may happen when you try to access a private or protected symbol (property or method) on a Java class.

Although the Groovy language is designed to be permissive when it comes to access control (meaning that it ignores the private and protected keywords in many scenarios), the Better PDF Exporter app uses an extended access control implementation that guarantees higher level of security. It guards against malicious Groovy scripts by "sandboxing" the Groovy code within the JVM.


class Foo {
	private def privateProperty = "PRIVATE_PROPERTY"

	private def privateMethod() {}

class Bar extends Foo {
	def accessPrivateProperty() {
		// throws groovy.lang.MissingPropertyException:
		// No such property: privateProperty for class: Bar

	def accessPrivateMethod() {
		// throws groovy.lang.MissingMethodException:
		// No signature of method: Bar.privateMethod() is applicable for argument types: ()

// throws org.codehaus.groovy.control.MultipleCompilationErrorsException:
// The class 'Baz' has an incorrect modifier private.
private class Baz {}

To fix the problem, your code must respect the access modifier rules:

  • If the protected or private symbol is in your Groovy script, change that to public. (You can just remove the access modifier, as the default visibility in Groovy is public.)
  • If it isn't, check the documentation (Javadoc) of the symbol and its encompassing class to see if there are public alternatives.
I get MissingPropertyException, MissingMethodException or CacheAccessControlException in a Groovy script.

These may happen when you try to work with a blacklisted Java class that is disallowed to use.

Note that importing a blaclisted class is possible, but the first time when you try to "actually work" with it (instantiate it, access its properties, call its methods, etc.), an exception like this will be thrown:

java.lang.RuntimeException: org.apache.velocity.exception.MethodInvocationException:
	Invocation of method 'getBar' in class FooTool threw exception org.codehaus.groovy.reflection.CacheAccessControlException:
Caused by: org.codehaus.groovy.reflection.CacheAccessControlException:
	Groovy object can not access method getBaz cacheAccessControlExceptionOf class com.acme.BazBuilder with modifiers "public static"
Caused by: access denied ("java.lang.reflect.ReflectPermission" "suppressAccessChecks")

It means that the getBar() method in your FooTool Groovy class tries to call com.acme.BazBuilder.getBaz(), but the com.acme.BazBuilder class is disallowed.

In the background, the Better PDF Exporter app checks each class against a blacklist. It guards against malicious Groovy scripts by limiting the classes available for the Groovy code.

To fix the problem, do not use the disallowed class! (It is disallowed for a good reason.) Find an alternative that is allowed, or replace it by writing the corresponding logic your in Groovy script.

Font-related problems

I see '#' characters instead of Cyrillic / Chinese / Japanese / etc. characters in the PDF files.

The most typical problem with fonts is that your document contains a character, but its glyph (symbol) is not available in the supplied font. For example, your issue description contains a Chinese character, but the supplied font does not contain any Asian glyph.

When the glyph for a character is not found, the renderer will replace it with the hash character '#' in the final PDF document. It means that seeing unexpected hash characters in the document is the typical indicator of the problem. Please note that even with this, the PDF document will be successfully rendered and will be a valid file.

Depending on the number and importance of the missing glyphs:

  1. The document may be usable if only a single unimportant glyph was missing (like an emoji).
  2. The document may be unusable if a high number of important glyphs were missing (like all Kanji and Kana in a Japanese document).

If it is the latter, use automatic fonts.

I see "Times" or "Times New Roman" being used in my PDF instead of the custom font I set in the template.

When you are trying to use a font family in the FO template, but the corresponding font is not found by the renderer, it will use "Times" instead. Unexpectedly seeing "Times" indicates that the custom font is not properly configured.

Review your custom font configuration and check whether the font family name is correctly set to the font-family="myfont" attribute. (If the font file is not available at the URL you specify, you will get an error message in the PDF file instead of rendering the text with "Times" or "Times New Roman".)

I see "java.lang.UnsupportedOperationException: ... not yet supported" exceptions when using a custom font.

Certain fonts may use special features known as "complex scripts" which are not yet supported by the PDF renderer. For example, the Roboto font is known to cause this issue.

If you are working with European languages only, you can safely disable the "complex scripts" feature:

  1. Login to Jira as administrator.
  2. Go to AppsManage your appsPDF Templates.
  3. Open the fop-config.xml file.
  4. Apply the change explained at point 3 in the Disabling complex scripts section.
  5. Save your changes.

Dashboard-related problems

Some of my gadgets are exported in a loading/incomplete state.

If a gadget loads slowly, our renderer engine might capture it before the gadget has a chance to display its final content. To fix this, see this guide.

I can't export the complete content of a wide gadget on my dashboard.

When you export an unusually wide gadget (e.g. a wide table with many columns), its content might not perfectly fit into the screenshot created by the renderer engine using the default width. To fix this, see this guide.

I get an "Unexpected system error! Try again later." message when exporting any of my dashboards.

If you activated the IP allowlisting feature on your Jira Cloud site, it will block the Better PDF Exporter app from accessing your dashboards. To fix this, just add the IP address to the list of allowed IP addresses. This static IP address is used by this app only, so adding it is perfectly safe!

Other problems

I see "Quota reached!" and "Hardly any quota left!" messages.

Jira data exports are resource-intensive tasks in general. Even more so, if they require extensive network communication between the Jira Cloud app and the Jira REST API, or if they execute computation-heavy Groovy scripts. To protect resources, Better PDF Exporter implements a quota system.

In the quota system, two factors are limited:

  1. the number of exports made within an hour
  2. the total duration of exports made within an hour

It means that you can run long export tasks, but less frequently, or short export tasks, but continuously. The app notifies you when you are near to the end of your quota to avoid bad surprises. If you eventually run out of quota, you just have to wait until the next hour and try again.

Important: please note that paid licenses enjoy a much larger quota than evaluation ones! It is because by paying the subscription fee (after the evaluation period is over), you help us in paying the AWS operational costs, which in turn allows us offer you a larger quota.

Table borders and underlines are blurred and are drawn with varying line thickness.

When viewing a PDF file in Adobe Reader, especially those with tables and lines, some lines may look thicker than other lines and even different sections of the same line may look somewhat blurry. It is caused by the "Enhance thin lines" feature of Adobe Reader, designed for lower resolution CRT monitors.

To enhance the look, turn off the feature in your Adobe Reader: navigate to EditPreferencesPage Display and uncheck the Enhance thin lines option. There is an additional option called Smooth line art that can make your lines laser-sharp, but can also cause other visual artifacts at line junctions (e.g. borders at the table corners). Find the combination that works best for you.

Unfortunately, these display settings are local (specific to your computer), not attributes of the PDF file itself.


Ask us any time.