# Tag.configure max recursion depth exceeded

**URL:** <https://forum.inductiveautomation.com/t/tag-configure-max-recursion-depth-exceeded/54090>\
**Category:** Ignition\
**Tags:** ignition81, perspective, scripting\
**Created:** [December 14, 2021, 10:19am UTC](https://forum.inductiveautomation.com/t/tag-configure-max-recursion-depth-exceeded/54090 "2021-12-14T10:19:48Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![flavien](https://avatars.discourse-cdn.com/v4/letter/f/f475e1/32.png) [@flavien](https://forum.inductiveautomation.com/u/flavien)\
**Post date:** [December 14, 2021, 10:19am UTC](https://forum.inductiveautomation.com/t/tag-configure-max-recursion-depth-exceeded/54090/1 "2021-12-14T10:19:48Z")

</div>

Hi,

I work on a script which add an alarm in tags.  
I use system.tag.getConfiguration() to get json tag and I add an alarm in 'alarms' key.  
My config before adding new alarm :

```auto
{
  "tagGroup": "PHPScriptExecution",
  "expression": "runScript(\"shared.alarms.daily(\"+{device_id}+\",\"+{project_id}+\",\"+{dailyHour1}+\",\"+{dailyHour2}+\")\")",
  "alarms": [],
  "query": "SELECT avg(value) FROM admin.m_data WHERE device_id\u003d{device_id} and project_id\u003d{[~]project_id} and datetime \u003e\u003d DATE_FORMAT(now()-interval 1 day,\u0027%Y-%m-%d 00:00:00\u0027) and datetime \u003c DATE_FORMAT(now()-interval 1 day,\u0027%Y-%m-%d 23:59:59\u0027)",
  "dataType": "Float4",
  "writePermissions": "{\"type\":\"AllOf\",\"securityLevels\":[]}",
  "executionMode": "TagGroupRate",
  "readOnly": false,
  "enabled": true,
  "path": "[test]ACW-TH 1CD279/value_daily",
  "readPermissions": "{\"type\":\"AllOf\",\"securityLevels\":[]}",
  "datasource": "",
  "tagType": "AtomicTag",
  "name": "value_daily",
  "valueSource": "expr"
}

```

My config after :

```auto
{
  "tagGroup": "PHPScriptExecution",
  "expression": "runScript(\"shared.alarms.daily(\"+{device_id}+\",\"+{project_id}+\",\"+{dailyHour1}+\",\"+{dailyHour2}+\")\")",
  "alarms": [
    {
      "activePipeline": "alarm-pipelines/home_pipeline",
      "setpointA": 18,
      "CustomEmailSubject": {
        "bindType": "Expression",
        "value": "concat(\"[ALARME] \",if(isNull(jsonGet({[~]project_info.value},\u0027outputs\u0027)),\u0027#titleError\u0027,jsonGet({[~]project_info.value},\u0027outputs[0].title\u0027)),\" : \",{name})"
      },
      "setpointB": 25,
      "displayPath": {
        "bindType": "Expression",
        "value": "concat(\u0027user/\u0027,{database},\u0027/\u0027,toStr(toInt({alarm_id})),\u0027/\u0027,{name})"
      },
      "priority": "High",
      "enabled": true,
      "mode": "OutsideValues",
      "name": "confort test",
      "alarm_id": 162,
      "inclusiveA": false,
      "CustomEmailMessage": {
        "bindType": "Expression",
        "value": "concat(\"Valeur : \\\"\",{setpointA},\"\\\" | Type : Est \\xe9gale xe0 \",\" | \",\"Valeur en alerte : moyenne sur \\\"\",{nb_hours},\"\\\" heures : \\\"\",{value})\")"
      },
      "inclusiveB": false
    }
  ],
  "query": "SELECT avg(value) FROM admin.m_data WHERE device_id\u003d{device_id} and project_id\u003d{[~]project_id} and datetime \u003e\u003d DATE_FORMAT(now()-interval 1 day,\u0027%Y-%m-%d 00:00:00\u0027) and datetime \u003c DATE_FORMAT(now()-interval 1 day,\u0027%Y-%m-%d 23:59:59\u0027)",
  "dataType": "Float4",
  "writePermissions": "{\"type\":\"AllOf\",\"securityLevels\":[]}",
  "executionMode": "TagGroupRate",
  "readOnly": false,
  "enabled": true,
  "path": "[test]ACW-TH 1CD279/value_daily",
  "readPermissions": "{\"type\":\"AllOf\",\"securityLevels\":[]}",
  "datasource": "",
  "tagType": "AtomicTag",
  "name": "value_daily",
  "valueSource": "expr"
}

```

I have error below :

> Blockquote  
> com.inductiveautomation.ignition.common.script.JythonExecException  
> Traceback (most recent call last):  
> File "function:runAction", line 5, in runAction  
> File "module:alarm", line 1364, in createAlarm  
> RuntimeError: maximum recursion depth exceeded (Java StackOverflowError)  
> at org.python.core.Py.RuntimeError(Py.java:157)  
> at org.python.core.Py.JavaError(Py.java:540)  
> at org.python.core.Py.JavaError(Py.java:538)  
> at org.python.core.PyReflectedFunction. **call** (PyReflectedFunction.java:192)  
> at com.inductiveautomation.ignition.common.script.ScriptManager$ReflectedInstanceFunction. **call** (ScriptManager.java:546)  
> at org.python.core.PyObject. **call** (PyObject.java:494)  
> at org.python.core.PyObject. **call** (PyObject.java:498)  
> at org.python.pycode.\_pyx9885.createAlarm$20(module:alarm:1388)  
> at org.python.pycode.\_pyx9885.call\_function(module:alarm)  
> at org.python.core.PyTableCode.call(PyTableCode.java:173)  
> at org.python.core.PyBaseCode.call(PyBaseCode.java:134)  
> at org.python.core.PyFunction. **call** (PyFunction.java:416)  
> at org.python.pycode._pyx10296.runAction$1(function:runAction:12)  
> at org.python.pycode.pyx10296.call\_function(function:runAction)  
> at org.python.core.PyTableCode.call(PyTableCode.java:173)  
> at org.python.core.PyBaseCode.call(PyBaseCode.java:306)  
> at org.python.core.PyFunction.function\_\_\_call_(PyFunction.java:474)  
> at org.python.core.PyFunction. **call** (PyFunction.java:469)  
> at org.python.core.PyFunction. **call** (PyFunction.java:464)  
> at com.inductiveautomation.ignition.common.script.ScriptManager.runFunction(ScriptManager.java:849)  
> at com.inductiveautomation.ignition.common.script.ScriptManager.runFunction(ScriptManager.java:831)  
> at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$TrackingProjectScriptManager.runFunction(ProjectScriptLifecycle.java:689)  
> at com.inductiveautomation.ignition.common.script.ScriptManager$ScriptFunctionImpl.invoke(ScriptManager.java:1000)  
> at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$AutoRecompilingScriptFunction.invoke(ProjectScriptLifecycle.java:754)  
> at com.inductiveautomation.perspective.gateway.script.ScriptFunctionHelper.invoke(ScriptFunctionHelper.java:136)  
> at com.inductiveautomation.perspective.gateway.action.ScriptAction.runAction(ScriptAction.java:71)  
> at com.inductiveautomation.perspective.gateway.model.ActionCollection$ActionSequence$ExecuteActionsTask.lambda$call$0(ActionCollection.java:263)  
> at com.inductiveautomation.perspective.gateway.api.LoggingContext.mdc(LoggingContext.java:54)  
> at com.inductiveautomation.perspective.gateway.model.ActionCollection$ActionSequence$ExecuteActionsTask.call(ActionCollection.java:252)  
> at com.inductiveautomation.perspective.gateway.model.ActionCollection$ActionSequence$ExecuteActionsTask.call(ActionCollection.java:221)  
> at com.inductiveautomation.perspective.gateway.threading.BlockingTaskQueue$TaskWrapper.run(BlockingTaskQueue.java:154)  
> at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)  
> at java.base/java.util.concurrent.FutureTask.run(Unknown Source)  
> at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)  
> at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)  
> at com.inductiveautomation.perspective.gateway.threading.BlockingWork$BlockingWorkRunnable.run(BlockingWork.java:42)  
> at java.base/java.lang.Thread.run(Unknown Source)  
> Caused by: org.python.core.PyException  
> Traceback (most recent call last):  
> File "function:runAction", line 5, in runAction  
> File "module:alarm", line 1364, in createAlarm  
> RuntimeError: maximum recursion depth exceeded (Java StackOverflowError)

Thanks for your help. 🥰

---

<div class="post-metadata">

**Author:** ![flavien](https://avatars.discourse-cdn.com/v4/letter/f/f475e1/32.png) [@flavien](https://forum.inductiveautomation.com/u/flavien)\
**Post date:** [December 14, 2021, 10:22am UTC](https://forum.inductiveautomation.com/t/tag-configure-max-recursion-depth-exceeded/54090/2 "2021-12-14T10:22:44Z")

</div>

Script row concerned :

```auto
tagAlarmsCnf = tagCnf['alarms']
tagAlarmsCnf.append(inputsConfig)
tagCnf['alarms'] = tagAlarmsCnf
	
collisionPolicy = "o"
tagRes = system.tag.configure(baseTagPath, [tagCnf], collisionPolicy)

```

---

<div class="post-metadata">

**Author:** ![mpoulsen921](https://avatars.discourse-cdn.com/v4/letter/m/b4bc9f/32.png) [@mpoulsen921](https://forum.inductiveautomation.com/u/mpoulsen921)\
**Post date:** [December 14, 2021, 11:30am UTC](https://forum.inductiveautomation.com/t/tag-configure-max-recursion-depth-exceeded/54090/3 "2021-12-14T11:30:05Z")

</div>

Hi,  
I don't know how you have made the whole script but the very last row in the error code tells me that you are making too many recursive calls to that same function.

By googling that Runtime Error I get the following message:

> The “maximum recursion depth exceeded in comparison” error is **raised** when you try to execute a function that exceeds Python's built in recursion limit. You can fix this error by rewriting your program to use an iterative approach or by increasing the recursion limit in Python

Are you adding the same alarm to all of your tags at once? Try limiting the code to just add the alarm to a single tag and see if that solves the issue.  
You will probably need to limit how many times you call the recursive function.

---

<div class="post-metadata">

**Author:** ![flavien](https://avatars.discourse-cdn.com/v4/letter/f/f475e1/32.png) [@flavien](https://forum.inductiveautomation.com/u/flavien)\
**Post date:** [December 14, 2021, 1:25pm UTC](https://forum.inductiveautomation.com/t/tag-configure-max-recursion-depth-exceeded/54090/4 "2021-12-14T13:25:47Z")

</div>

I configure only one tag. 🤨  
May be because it’s a UDT instance.

My entire script :

```auto
def createAlarm(inputs):
		
	import features
	try:
		inputs=dict(inputs)
	except:
		return {'state':False,'message':u"La variable d'entrée n'est pas un dictionnaire.","outputs":[], "meta":features.msgMeta(False)}
		
	#On récupère les infos de l'alarme
	inputsKeys = inputs.keys()
	#Le tagPath
	if "tagPath" in inputsKeys:
		tagPath = inputs['tagPath']
	else:
		return {'state':False,'message':u"La variable tagPath n'est pas indiquée.","outputs":[], "meta":features.msgMeta(False)}
	
	#Le database
	if "database" in inputsKeys:
		database = inputs['database']
	else:
		return {'state':False,'message':u"La variable database n'est pas indiquée.","outputs":[], "meta":features.msgMeta(False)}
	
	#Le database
	if "tagName" in inputsKeys:
		tagName = inputs['tagName']
	else:
		return {'state':False,'message':u"La variable database n'est pas indiquée.","outputs":[], "meta":features.msgMeta(False)}
		
	#On compose le nom complet du tag
	fullTagPath = "["+database+"]"+tagPath+"/"+tagName
	baseTagPath = "["+database+"]"+tagPath
	
	#ON récupère la config du tag
	tags = system.tag.getConfiguration(fullTagPath)
	
	if len(tags) == 0:
		return {'state':False,'message':u"Aucun tag n'a été trouvé pour le capteur indiqué. Si le problème persiste, contacter l'administrateur.","outputs":[], "meta":features.msgMeta(False)}
	else:
		tagCnf = tags[0]
		if 'tagType' in tagCnf.keys():
			tagType = tagCnf['tagType']
			
			if tagType == "Unknown":# Cas où le tag n'existe pas
				return {'state':False,'message':u"Le tag de ce capteur n'existe pas. Nom : "+tagCnf['path']+". Si le problème persiste, contacter l'administrateur.","outputs":[], "meta":features.msgMeta(False)}	
					
	
	alarmCols = ['alarm_name','description','alarm_type','alarm_mode','alarm_agg','device_id','project_id','limit1','limit2','unit','recipients','mode','state','email_trigger','isPreset']
	queryCols = []
	queryVars = []
	query = "INSERT INTO alarms_config ("
	questionMarks = ""
	
	for alarmCol in alarmCols:
		if alarmCol in inputsKeys:
			queryCols.append(alarmCol)
			query += " %s,"
			questionMarks += " ?,"
			queryVars.append(inputs[alarmCol])
	
	txId = system.db.beginTransaction(database="base_administrateur",timeout=5000)
	
	query = query[:-1] % tuple(queryCols) + ") VALUES ("+questionMarks[:-1]+")"
	alarm_id = system.db.runPrepUpdate(query,queryVars,"base_administrateur",tx=txId, getKey=1)
	try:
		alarm_id = system.db.runPrepUpdate(query,queryVars,"base_administrateur",tx=txId, getKey=1)
	except:
		errors = {'state':False,'message':u"Une erreur s'est produite lors de l'ajout de l'alarme dans la base de données.","outputs":[], "meta":features.msgMeta(False)}
	else:
		errors = {'state':True,'message':u"L'alarme a bien été créée.","outputs":[], "meta":features.msgMeta(True)}
		
	#Gestion de l'erreur
	if errors['state']==False:
		# ...then rollback the transaction
		system.db.rollbackTransaction(txId)
	else:
		# ON met l'alarm_id dans la configuration du tag
		inputsConfig = inputs['config']
		inputsConfig['alarm_id'] = alarm_id
		
		#On ajoute sa configuration dans la variable des alarmes
		tagAlarmsCnf = tagCnf['alarms']
		tagAlarmsCnf.append(inputsConfig)
		tagCnf['alarms'] = tagAlarmsCnf
		
		collisionPolicy = "o"
		tagRes = system.tag.configure(baseTagPath, [tagCnf], collisionPolicy)
	
			
		if tagRes[0].isGood():
			# Si le tag a été mis à jour on ajoute sa configuration dans la table alrms_config
			try:
				system.db.runPrepUpdate("UPDATE alarms_config SET config = ? WHERE alarm_id = ?",[features.encodeJSON(inputs['config']),alarm_id],"base_administrateur",tx=txId)
			except:
				errors = {'state':False,'message':u"Une erreur s'est produite lors de la mise à jour de l'alarme dans la base de données.","outputs":[], "meta":features.msgMeta(False)}
			else:
				errors = {'state':True,'message':u"L'alarme a bien été créée.","outputs":[], "meta":features.msgMeta(True)}
				
			if errors['state']:
				# Otherwise, commit it
				system.db.commitTransaction(txId)
			else:
				system.db.rollbackTransaction(txId)
				
		else:
			system.db.rollbackTransaction(txId)
			errors = {'state':False,'message':u"Une erreur s'est produite lors de la mise à jour du tag de l'alarme.","outputs":[], "meta":features.msgMeta(False)}
	
	system.db.closeTransaction(txId)
	
	return errors 

```

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [December 14, 2021, 3:29pm UTC](https://forum.inductiveautomation.com/t/tag-configure-max-recursion-depth-exceeded/54090/5 "2021-12-14T15:29:51Z")

</div>

How are you calling this function ?

Unrelated : may I suggest you split this up in more specialized functions ? This kind of script is a pain to maintain/debug, especially if you’re picking up the job after someone else.  
I’ve been re-writing scripts like this, left there by someone else, for the last few months because they’ve come to a point where it’s easier to just rewrite than fix.  
This one is still readable, but after a couple fixes/reworks…

---

<div class="post-metadata">

**Author:** ![flavien](https://avatars.discourse-cdn.com/v4/letter/f/f475e1/32.png) [@flavien](https://forum.inductiveautomation.com/u/flavien)\
**Post date:** [December 14, 2021, 3:58pm UTC](https://forum.inductiveautomation.com/t/tag-configure-max-recursion-depth-exceeded/54090/6 "2021-12-14T15:58:29Z")

</div>

I call it in a onActionPerformed button.

Script is stored in Project Library.

---

<div class="post-metadata">

**Author:** ![osolorzano](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/osolorzano/32/6432_2.png) [@osolorzano](https://forum.inductiveautomation.com/u/osolorzano)\
**Post date:** [December 14, 2021, 10:23pm UTC](https://forum.inductiveautomation.com/t/tag-configure-max-recursion-depth-exceeded/54090/7 "2021-12-14T22:23:10Z")

</div>

It’s a little hard to tell but we have a similar issue that was written up a little while back where encoding the config from `system.tag.getConfiguration()` to json can throw this error due to an internal issue with Ignition.  
If the error is occurring on:

```auto
features.encodeJSON(inputs['config'])

```

it _may_ work if you change it to

```auto
features.encodeJSON(str(inputs['config']))

```

---

<div class="post-metadata">

**Author:** ![flavien](https://avatars.discourse-cdn.com/v4/letter/f/f475e1/32.png) [@flavien](https://forum.inductiveautomation.com/u/flavien)\
**Post date:** [April 14, 2022, 2:00pm UTC](https://forum.inductiveautomation.com/t/tag-configure-max-recursion-depth-exceeded/54090/8 "2022-04-14T14:00:01Z")

</div>

Can I use : sys.setrecursionlimit(5000) ?

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [April 14, 2022, 3:54pm UTC](https://forum.inductiveautomation.com/t/tag-configure-max-recursion-depth-exceeded/54090/9 "2022-04-14T15:54:31Z")

</div>

No. It’s a bug in the Java code, and the `sys` flag only affects Jython’s execution environment.  
Also, the ‘fix’ for a StackOverflowError is pretty much never “make the stack larger”. It’s a programming error (on our part, not yours) to fix.

---

<div class="post-metadata">

**Author:** ![flavien](https://avatars.discourse-cdn.com/v4/letter/f/f475e1/32.png) [@flavien](https://forum.inductiveautomation.com/u/flavien)\
**Post date:** [April 15, 2022, 8:43am UTC](https://forum.inductiveautomation.com/t/tag-configure-max-recursion-depth-exceeded/54090/10 "2022-04-15T08:43:44Z")

</div>

I optimized my script and it works:

Below part of script updated.  
Before →

```auto
#Gestion de l'erreur
if errors['state']==False:
	# ...then rollback the transaction
	system.db.rollbackTransaction(txId)
else:
	# ON met l'alarm_id dans la configuration du tag
	inputsConfig = inputs['config']
	inputsConfig['alarm_id'] = alarm_id
	
	#On ajoute sa configuration dans la variable des alarmes
	tagAlarmsCnf = tagCnf['alarms']
	tagAlarmsCnf.append(inputsConfig)
	tagCnf['alarms'] = tagAlarmsCnf
	
	collisionPolicy = "o"
	tagRes = system.tag.configure(baseTagPath, [tagCnf], collisionPolicy)

```

After →

```auto
#Gestion de l'erreur
if errors['state']==False:
	# ...then rollback the transaction
	system.db.rollbackTransaction(txId)
else:
	# ON met l'alarm_id dans la configuration du tag
	inputs['config']['alarm_id'] = alarm_id
			
	#On ajoute sa configuration dans la variable des alarmes
	if "alarms" in tags[0].keys():
		tags[0]['alarms'].append(inputs['config'])
	else:
		tags[0]['alarms'] = [inputs['config']]
						
	tagCnfForConfigure = [
	            {
	                "alarms":tags[0]['alarms'],
	                "name":tagName
	            }
	        ]
	
	collisionPolicy = "o"
	tagRes = system.tag.configure(baseTagPath, tagCnfForConfigure, collisionPolicy)

```
