Script weird behavior with system.perspective.openPopup

Hello everyone. I'm facing a weird issue with a script that gives me error only the first time I try to execute it, then it doesn't work also but doesn't show the error again!
The error is:

([edge]Test/MoveToPanelHome/Trigger, valueChanged) Error executing tag event script: Traceback (most recent call last): File "<tagevent:valueChanged>", line 11, in valueChanged File "<module:OPCMethods>", line 63, in callMethod File "<module:OPCMethods>", line 63, in callMethod at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.lambda$operateOnPage$0(AbstractScriptingFunctions.java:64) at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnSession(AbstractScriptingFunctions.java:120) at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnPage(AbstractScriptingFunctions.java:47) at com.inductiveautomation.perspective.gateway.script.PerspectiveScriptingFunctions.popupAction(PerspectiveScriptingFunctions.java:758) at com.inductiveautomation.perspective.gateway.script.PerspectiveScriptingFunctions.openPopup(PerspectiveScriptingFunctions.java:240) 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.IllegalArgumentException: java.lang.IllegalArgumentException: No perspective page attached to this thread.

I'm calling a script from project library on a tag value changed, and change the trigger tag using a button in perspective. The scripts are the following sequentially:
First script on the button

def runAction(self, event):
	system.tag.configure("[edge]Test/GetCentroid", [{"name" : "Trigger", "sessionId" : str(self.session.props.id)}], "m")
	system.tag.writeBlocking(["[edge]AB_Test/EP_Job_GetCentroid/Trigger"], [True])

Second script on the tag value changed

def valueChanged(tag, tagPath, previousValue, currentValue, initialChange, missedEvents):
	if (not initialChange) and (currentValue.value == True) and (currentValue.value != previousValue.value) and (currentValue.quality.good) and (previousValue.quality.good):
		# Parsing Method path in AB and EP
		pathEP = '/'.join(tagPath.split("/")[:-1])
		pathAB = tag['parameters']['ABPath']
		
		# Parsing sessionId
		sessionId = tag['sessionId']
		
		# Call the Method
		OPCMethods.callMethod(pathEP, pathAB, sessionId)

Third script in project library

def callMethod(pathEP, pathAB, thisSession):
	logger = system.util.getLogger("DiagMethod")
	logger.info(thisSession)
	# Reading OPC method params (OPC Connection Name, OPC Server Namespace, ObjectID, MethodID)
	opc = system.tag.readBlocking(["[edge]EastmanPro/OPCConnection", "[edge]EastmanPro/Namespace", pathEP + "/ObjectId", pathEP + "/MethodId"])
	conn, ns = opc[0].value, opc[1].value
	objectId, methodId = ns + opc[2].value, ns + opc[3].value
	
	# Init args and outputs
	args = []
	outs = []
	
	# Browse AB UDT to get args and outs
	try:
		udtAB = system.tag.browse(pathAB)
	except Exception as e1:
		logger.warning("Error1" + str(e1))
		try:
			system.perspective.openPopup("pathABError1", "Popups/ErrorBox", params = {"message" : "Error 1: Invalid AB Path.\n 'ABPath' parameter that refers to method UDT in AB PLC is invalid."}, title = "Error", sessionId = thisSession)
		except Exception as e1hf:	
			logger.error("Error1HF" + str(e1hf))

		return
		
	# Read args values and outs names/number
	for tag in udtAB:
		if "Arg" in tag["name"]:
			args.append(system.tag.readBlocking(pathAB + "/" + tag["name"])[0].value)
		if "Return" in tag["name"]:                            #tag["name"] == "Return1" or tag["name"] == "Return2":
			outs.append(str(tag["fullPath"]))
	
	# Sort args and outs
	args = sorted(args)
	outs = sorted(outs)

	# Call the method		
	try:
		method = system.opcua.callMethod(conn, objectId, methodId, args)
	except Exception as e2:
		logger.info(" ".join(list((str(conn), str(objectId), str(methodId), str(args)))))
		logger.error("Error2: " + str(e2))
		try:
			system.perspective.openPopup("methodCallError2", "Popups/ErrorBox", params = {"message" : "Error 2: Method call failed.\nOne of the following parameters is invalid:\n  - Ignition OPC client connection name.\n  - EastmanPro OPC server Namespace.\n  - ObjectId (NodeId of the Object Node the Method is a member of).\n  - MethodId.\n  - List of Inputs (check data types and order)."}, title = "Error", sessionId = thisSession)
		except Exception as e2hf:
			logger.error("Error2HF: " + str(e2hf))

			
	# Write StatusCodes return for Call and inputs
	statPaths = [pathEP + "/StatusCode_Call", pathEP + "/StatusCode_Inputs"]
	statCall = [str(method[0][0]), method[0][1], method[0][2]]
	statInputs = system.dataset.toDataSet(["Code", "Name", "Description"], [list(i) for i in method[1]])
	
	system.tag.writeBlocking(statPaths, [statCall, statInputs])

	# Write back to the Return (Assuming method return status as a 1st value eg. [Return, Return1. Return2])
	try:
		system.tag.writeBlocking(outs, method[2])
	except Exception as e3:
		logger.error("Error3: " + str(e3) + " Paths: " + str(outs) + " Returns: " + str(method[2]))

	# Prompt the success message and Trigger tag reset option
	try:
		system.perspective.openPopup("methodCallSuccess", "Popups/DoneBox", params = {"message" : "Method has been called successfully!\nDo you need to reset AB Trigger tag?", "pathAB" : pathAB} if method[0][0] == 0 else {"message" : "Method call failed!\nDo you need to reset AB Trigger tag?", "pathAB" : pathAB}, title = "Done", sessionId = thisSession)
	except Exception as df:
		logger.error("DoneFail" + str(df))

	

Now I have three questions:

  • Why do I still get this error (No perspective page attached to this thread.No perspective page attached to this thread.), although I'm passing the sessionId correctly?
  • Why does the error appear in the logs only the first execution, then never appear until I restart Ignition service?
  • Why don't (try, except) handle the error (first execution or even after that)?

Thanks and sorry for the long question :smiley:


A session, by itself, cannot open a popup. You need a page.

Ignition deliberately suppresses repeat errors/warnings.

Jython's Exception is not related to java's Exception hierarchy, and cannot catch java errors or exceptions. Typically, you'd use two except clauses. One catching java.lang.Throwable, the second catching jython's Exception.

Thank you very much @pturmel. It's clear now. Regarding the third question, I totally understand your explanation, but I don't know to implement it. If you can give me an example I would be grateful.

Use something like this:

Great! Thank you for the support