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 thereportvariable, not a Java NPE from insideReportViewer.print. The trace proves the component was found and itsprintmethod 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 of0, 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.printframes in the cause. -
Adding
time.sleep()before the print. This is the worst option. Every frame in the trace runs onjava.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:
- A button's
actionPerformedscript (<event:actionPerformed>:7) callssystem.nav.openWindow. You can seeNavUtilities.openWindowandFPMIApp.openWindowin the trace. - The new window's
internalFrameActivatedscript (<event:internalFrameActivated>:3) callsdoClick()on a button. That is thePMIButton.doClick(PMIButton.java:68)frame. - That button's
actionPerformedrunsreport.print(None, 0)and throws atReportViewer.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.
- Open the
actionPerformedscript on the print button. This is the button that the window's activation or open script clicks. - Replace the four lines with the script below.
- 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 NullPointerExceptionlets Jython catch the Java exception directly. A bareexcept:would also hide real faults, such as a bad printer name. -
invokeLaterwith 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 fromtime.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
eventeach time. -
timer.running = 1is 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.
- Open the report window by hand with the heaviest parameters production will use, such as the widest date range or the most rows.
- 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.
- Set to at least twice the slowest time you measured.
- 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
- Open the client console at Help > Diagnostics > Console.
- Trigger the full chain from the original button: open the window, let the activation script click the print button, and let the print run.
- Confirm the console shows
Report printed on attempt Nwith 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. - Confirm no
NullPointerExceptiontraceback appears in the console or in an error popup. - Confirm the Timer starts only after the printout reaches the printer.
- 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.
- Click away from the report window and back. If it prints again, move the
doClick()call frominternalFrameActivatedtointernalFrameOpened.
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.
- Read the release notes for each 7.8.x build after
b2015101414. Look for Report Viewer print or load-state fixes. - After upgrading, keep the retry script. It costs nothing when the first attempt succeeds, and it still protects against slow loads.
- 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.