Cannot invoke Object.getClass() because "o" is null - Error

Hi there, I'm having trouble tracking down a script that is clearly trying to open a pop-up window with a list of current alarms, this has occurred after an upgrade from 7.9 to 8.1. Were working on getting everything up and running and have hit a bit of a snag.

Full Error:

Traceback (most recent call last):
  File "<event:actionPerformed>", line 2, in <module>
	at org.python.core.PyJavaType.wrapJavaObject(PyJavaType.java:120)
	at com.inductiveautomation.factorypmi.application.script.PyComponentWrapper.<init>(PyComponentWrapper.java:52)
	at com.inductiveautomation.factorypmi.application.script.builtin.WindowUtilities.lambda$getParentWindow$1(WindowUtilities.java:513)
	at com.inductiveautomation.factorypmi.application.script.builtin.WindowUtilities.doGUIAction(WindowUtilities.java:851)
	at com.inductiveautomation.factorypmi.application.script.builtin.WindowUtilities.getParentWindow(WindowUtilities.java:511)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
java.lang.NullPointerException: java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "o" is null

	at org.python.core.Py.JavaError(Py.java:545)
	at org.python.core.Py.JavaError(Py.java:536)
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:192)
	at com.inductiveautomation.ignition.common.script.ScriptManager$ReflectedInstanceFunction.__call__(ScriptManager.java:553)
	at org.python.core.PyObject.__call__(PyObject.java:461)
	at org.python.core.PyObject.__call__(PyObject.java:465)
	at org.python.pycode._pyx393.f$0(<event:actionPerformed>:93)
	at org.python.pycode._pyx393.call_function(<event:actionPerformed>)
	at org.python.core.PyTableCode.call(PyTableCode.java:173)
	at org.python.core.PyCode.call(PyCode.java:18)
	at org.python.core.Py.runCode(Py.java:1703)
	at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:804)
	at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.runActions(ActionAdapter.java:207)
	at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.invoke(ActionAdapter.java:300)
	at com.inductiveautomation.factorypmi.application.binding.action.RelayInvocationHandler.invoke(RelayInvocationHandler.java:57)
	at jdk.proxy2/jdk.proxy2.$Proxy63.actionPerformed(Unknown Source)
	at java.desktop/javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(Unknown Source)
	at java.desktop/java.awt.Component.processMouseEvent(Unknown Source)
	at java.desktop/javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.Component.processEvent(Unknown Source)
	at java.desktop/java.awt.Container.processEvent(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)
Caused by: java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "o" is null
	at org.python.core.PyJavaType.wrapJavaObject(PyJavaType.java:120)
	at com.inductiveautomation.factorypmi.application.script.PyComponentWrapper.<init>(PyComponentWrapper.java:52)
	at com.inductiveautomation.factorypmi.application.script.builtin.WindowUtilities.lambda$getParentWindow$1(WindowUtilities.java:513)
	at com.inductiveautomation.factorypmi.application.script.builtin.WindowUtilities.doGUIAction(WindowUtilities.java:851)
	at com.inductiveautomation.factorypmi.application.script.builtin.WindowUtilities.getParentWindow(WindowUtilities.java:511)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:190)
	... 49 more

Ignition v8.1.47 (b2025022612)
Java: Azul Systems, Inc. 17.0.13

80% sure this is the scripting that is calling and causing the above error.

# Define Variables
parentWindow = system.gui.getParentWindow(event)
screen = event.source.getGraphicsConfiguration().getBounds()
screenHorPos = screen.x
screenVertPos = screen.y
buttonX = event.source.getLocationOnScreen().x

# This accounts for the height of the footer if the popup is launched from the navigation footer window
if parentWindow.name == "Footer":
	buttonY = event.source.getLocationOnScreen().y - windowHeight
else:
	buttonY = event.source.getLocationOnScreen().y
	
buttonWidth = event.source.getSize().width	
buttonHeight = event.source.getSize().height
sourceX = abs(buttonX - screenHorPos)
sourceY = abs(buttonY - screenVertPos)
windowWidth = parentWindow.getWidth()
windowHeight = parentWindow.getHeight()
try:
	requiredRoles = parentWindow.getRootContainer().requiredRoles
	print "Parent Window Roles:", requiredRoles
except:
	print parentWindow.title, "has no requiredRoles parameter configured."
	requiredRoles = 'rolesNotConfigured'
	
# Define Which Popup to Open
popupPath = event.source.parent.popupPath

# Get all of the alarm tag paths
tagPaths = [event.source.parent.alarm0Path, event.source.parent.alarm1Path, event.source.parent.alarm2Path,
			event.source.parent.alarm3Path, event.source.parent.alarm4Path, event.source.parent.alarm5Path,
			event.source.parent.alarm6Path, event.source.parent.alarm7Path, event.source.parent.alarm8Path,
			event.source.parent.alarm9Path]

# Pare down the list of tagPaths to only those that are configured
tagPaths = list(filter(lambda a: a != '', tagPaths))

# Create a dictionary of tagPaths and fullTagPaths with the prov:default:/tag: prefix appended to each tag path
fullTagPaths = {}
for tagPath in tagPaths:
	fullTagPaths[tagPath] = "prov:default:/tag:" + tagPath + "*"
	#fullTagPaths.append("prov:default:/tag:" + tagPath + "*")

# Develop the alarm state filter. Ex: ["ActiveUnacked","ActiveAcked"]
alarmState = []
alarmState.append("ActiveUnacked")
alarmState.append("ActiveAcked")

# Get the description and priority information from the tagPaths list
alarmRows = []
for tagPath, fullTagPath in fullTagPaths.iteritems():
	alarmInfo = system.alarm.queryStatus(state=alarmState, path=[fullTagPath])
	alarmData = alarmInfo.getDataset()
	pyAlarmData = system.dataset.toPyDataSet(alarmData)
	
	for row in pyAlarmData:
		alarmDescription = row["DisplayPath"]
		alarmPriority = row["Priority"]
		alarmSource = tagPath
		newRow = [alarmDescription, alarmPriority, alarmSource]
		alarmRows.append(newRow)
		
headers = ["Description", "Priority", "Source"]
alarmDataset = system.dataset.toDataSet(headers, alarmRows)

# Sort the alarmDataset by priority, highest to lowest
sortedDataset = system.dataset.sort(alarmDataset, "Priority", 0)

# Open the popup window
try:
	popupHeight = 10
	alarmRowHeight = 35
	try:
		alarmData = system.dataset.toPyDataSet(sortedDataset)
		# Determine the number of alarms that are configured and active in the dataset, this will
		# set the height of the popup window.
		alarmCount = 0
		for row in alarmData:
			if row != '':
				popupHeight += alarmRowHeight
				alarmCount += 1
			else:
				pass
		if alarmCount > 0:
			popup = system.nav.openWindowInstance(popupPath, {'alarmDataset' : sortedDataset, 'popupHeight' : popupHeight,
				'sourceX': sourceX, 'sourceY': sourceY, 'buttonWidth': buttonWidth, 'buttonHeight': buttonHeight,'sourceWidth': windowWidth, 'sourceHeight': windowHeight})
		else:
			system.gui.messageBox("No active alarms.")
	except:
		pass
except:
	pass

When there are active alarms, I am getting a popup saying "No active alarms.", In the designer only am I getting the OP error message.

This is weird.

So this call internally does this:

        if (event.getSource() instanceof JComponent) {
            return IgnitionSwingUtilities.getAncestorOfClass(FPMIWindow.class, (JComponent) event.getSource());

Which then goes to this:

return new PyComponentWrapper(o);

Which, inside that constructor, does this:

        delegate = PyJavaType.wrapJavaObject(component);

Which, in Jython's internals, does this:

    public static PyObject wrapJavaObject(Object o) {
        PyObject obj = new PyObjectDerived(fromClass(o.getClass()));
        setProxyAttr(obj, o);
        return obj;
    }

Which is where the NPE is coming from - o is null, so there's no way to call getClass() on it.

Going backwards, that means the IgnitionSwingUtilities call is being hit, but is also returning null, meaning whatever component you passed in via the event object either was not a window or was not contained within a window.

Which should not be possible in Vision.

The stack suggests you're calling this from a button - anything funky about that button you can think of?