Resolving Ignition Report Viewer print NullPointerException

Mark Townsend8 min read
HMI / SCADAOther ManufacturerTroubleshooting
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

You press the button, the report window opens, and the client throws java.lang.NullPointerException at com.inductiveautomation.reporting.components.ReportViewer.print(ReportViewer.java:1021). Nothing prints. The Timer after the print call never starts. The build is Ignition v7.8.0 (b2015101414) on Java 1.8.0_65, and the script is only four lines:

report = event.source.parent.getComponent('Report Viewer')
report.print(None, 0)
timer = event.source.parent.getComponent('Timer')
timer.running = 1

The script is fine. It calls print() before the Report Viewer has any report to print.

Skip the fixes that never touch this NPE

Most people burn time on these first. None of them change the outcome.

  • Re-checking the component name. If getComponent('Report Viewer') had failed, you would get a Python error on the report variable, not a Java NPE from inside ReportViewer.print. The trace proves the component was found and its print method ran. Move on.
  • Fixing the curly quotes. Typographic quotes around 'Report Viewer' would cause a syntax error, not a runtime NPE. If the pasted script shows curly quotes, that is a display artifact. It is not your fault.
  • Swapping the print arguments. Passing a named printer instead of None, or turning the print dialog on instead of 0, only changes the printer and dialog choice. The null is the report document, not the printer.
  • Reinstalling printer drivers or Java. The exception is raised in Inductive Automation's reporting component before the call reaches the Java print subsystem. There are no javax.print frames in the cause.
  • Adding time.sleep() before the print. This is the worst option. Every frame in the trace runs on java.awt.EventDispatchThread. Sleeping there freezes the client UI. It can also block the component from finishing its load, so you get a frozen window and the same NPE.
  • Using one fixed delay. system.util.invokeLater(func, delay) with a single hard-coded delay works on the bench and fails in production. Report load time depends on your queries, the report complexity, and a round trip to the gateway. One number will not cover every run.

Read the call chain: print fires while the report is still loading

Read the stack trace from the bottom up. It shows a chain of scripts, not a single button press:

  1. A button's actionPerformed script (<event:actionPerformed>:7) calls system.nav.openWindow. You can see NavUtilities.openWindow and FPMIApp.openWindow in the trace.
  2. The new window's internalFrameActivated script (<event:internalFrameActivated>:3) calls doClick() on a button. That is the PMIButton.doClick(PMIButton.java:68) frame.
  3. That button's actionPerformed runs report.print(None, 0) and throws at ReportViewer.java:1021.

All three steps happen in the same event-thread pass that makes the window visible. The Report Viewer has only just started its load. It still has to run the report's data queries, make a gateway round trip, and generate the document. Until that finishes, the object print() needs is null.

The failure reproduces reliably whenever the report has not fully loaded when the script runs. In 7.8.0, no script property or method tells you the load is complete. The only signal is the NPE itself. That is why the workaround below uses the exception as its readiness check.

Also note that internalFrameActivated fires every time the window regains focus, not only when it opens. Even with a working retry, a user who clicks away and back will trigger another print. Use internalFrameOpened if you want one print per open.

Match the symptom to the cause

Symptom Cause First check
NPE at ReportViewer.print(ReportViewer.java:1021) every time print is triggered on window open Print called before the report finished loading Look for openWindow and doClick frames in the trace
Print works from a manual button press a few seconds after opening, fails when automated Same race; the manual press happens after the load completes Time from window open to print call
Fails only with large date ranges or heavy parameters Load time exceeds whatever delay you added Run the report's queries on their own and time them
Timer never starts after the error The NPE aborts the script before timer.running = 1 Script line order
Client freezes, then NPE anyway time.sleep() on the event thread blocking the load Search the event scripts for sleep
Error names the component or attribute, not ReportViewer.print Wrong component path or name, which is a different fault Component name in the Designer tree

Replace the one-shot print with a bounded retry

Treat the NPE as "not ready yet." Catch it, reschedule the attempt with system.util.invokeLater so the event thread stays free, and give up after a fixed number of tries.

  1. Open the actionPerformed script on the print button. This is the button that the window's activation or open script clicks.
  2. Replace the four lines with the script below.
  3. Leave the doClick() call in the window event as it is. The retry logic lives in the print button, so manual presses are covered too.

What each part does:

  • from java.lang import NullPointerException lets Jython catch the Java exception directly. A bare except: would also hide real faults, such as a bad printer name.
  • invokeLater with a delay puts the next attempt back on the event queue and returns right away. The component keeps loading between attempts. This is the key difference from time.sleep().
  • The component references are captured once at the top. The retries run after the original event has finished, so they should not rely on walking the tree from event each time.
  • timer.running = 1 is only reached after a successful print. In the original script, it sat after an unguarded call and never ran on failure. If that Timer closes the window or advances a sequence, it must not start before the print succeeds.

Size the retry window to your report's worst-case load

The two constants are tuning choices, not product timings. Measure your load time before you set them.

  1. Open the report window by hand with the heaviest parameters production will use, such as the widest date range or the most rows.
  2. Time how long it takes from the window opening to the report rendering in the viewer. Do this several times, and include a cold gateway cache if you can.
  3. Set to at least twice the slowest time you measured.
  4. Keep in the hundreds of milliseconds. Shorter intervals only add log noise. Longer ones add dead time after the load finishes.

If the worst case runs to tens of seconds, the retry is hiding a slow query. Fix the data source first: add indexes, narrow the ranges, or pre-aggregate. Then set the ceiling.

Move unattended printing off the client when you can

The race only exists because a client window has to open, load, and print in one sequence. If nobody needs to see the report before it prints, consider printing from the Reporting module's gateway-side schedule or actions instead of a Vision window.

  • This removes the window-open timing, the doClick() chain, and the dependency on a running client.
  • Check which scheduling and print actions your exact 7.8.x build supports in the Reporting module documentation before you commit to this design.
  • Keep the client-side retry for operator-triggered prints from the window.

Prove the fix under load before you sign it off

  1. Open the client console at Help > Diagnostics > Console.
  2. Trigger the full chain from the original button: open the window, let the activation script click the print button, and let the print run.
  3. Confirm the console shows Report printed on attempt N with N greater than 1 at least some of the time. N = 1 on every run means your test report loads too fast to exercise the race. Retest with heavy parameters.
  4. Confirm no NullPointerException traceback appears in the console or in an error popup.
  5. Confirm the Timer starts only after the printout reaches the printer.
  6. Force the failure path: point the report at a query that will not return within the ceiling, or temporarily set . Confirm the error box appears and the Timer stays stopped.
  7. Click away from the report window and back. If it prints again, move the doClick() call from internalFrameActivated to internalFrameOpened.

Plan the upgrade to a later 7.8.x build

This behavior was acknowledged as a defect in 7.8.0, with a fix targeted for a later 7.8.x release. The release carrying the fix is not identified here.

  1. Read the release notes for each 7.8.x build after b2015101414. Look for Report Viewer print or load-state fixes.
  2. After upgrading, keep the retry script. It costs nothing when the first attempt succeeds, and it still protects against slow loads.
  3. Re-run the verification steps above on the new build. Confirm that attempt 1 succeeds, or that the viewer now handles an early print call without an NPE.

FAQ

Does the Ignition 7.8 Report Viewer have a property that shows the report is loaded?

Not in 7.8.0. No script property or method reports load completion. The practical readiness check is to call print(), catch java.lang.NullPointerException, and retry later with system.util.invokeLater.

Can I use time.sleep() to wait for the report before printing?

No. Event scripts run on the Swing event dispatch thread, so time.sleep() freezes the client and can stall the report load it is waiting on. Use system.util.invokeLater(func, delayMs) in a bounded retry loop instead.

Does passing a printer name instead of None fix the NullPointerException?

No. The NPE is raised inside ReportViewer.print because the report document is not ready yet, not because of the printer argument. print(None, 0) is valid once the report has loaded.

Can I trigger the print from internalFrameActivated safely?

Only with the retry logic in place. Even then, internalFrameActivated fires every time the window regains focus, so you may get repeat prints. Use internalFrameOpened for one print per window open.

When should I contact Inductive Automation support about this error?

Contact support through official channels if the NPE persists after the retry reaches its full ceiling on a report that visibly renders in the viewer. Do the same if a later 7.8.x build still throws at ReportViewer.print after the report has loaded. Send the full client console trace, the exact build number, the Java version, and the measured load time.

Back to blog