# Unexpected Variable Value

**URL:** <https://forum.inductiveautomation.com/t/unexpected-variable-value/99820>\
**Category:** Ignition\
**Tags:** ignition81\
**Created:** [December 13, 2024, 8:05pm UTC](https://forum.inductiveautomation.com/t/unexpected-variable-value/99820 "2024-12-13T20:05:45Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![rbachman](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/rbachman/32/43718_2.png) [@rbachman](https://forum.inductiveautomation.com/u/rbachman)\
**Post date:** [December 13, 2024, 8:05pm UTC](https://forum.inductiveautomation.com/t/unexpected-variable-value/99820/1 "2024-12-13T20:05:45Z")

</div>

We have a function that we use for handling errors with our code. The intent is that an email is generated if we encounter an unexpected issue, and the email is sent both to the original developer and as well as to a group email inbox ( **Ignition** ) so that we can monitor issues with code across all locations and developers.

Occasionally we will have a very fast repeating error that will generate many emails in a very short period of time. When this happens, the group email inbox address is often added multiple times to the email even though we are confident that this is not in the code. Here is an example where the group email address ( **Ignition** ) is added multiple times to an email:

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/9/d/9dadaed71eb98b30b9b4b0c26f2c8c279029d1b6.png)

If there is a delay between the errors, this problem seems to go away and the emails only include one instance of the **Ignition** email address. Does Ignition, Java, or Jython somehow retain the **email** variable from the exception function and reuse it when that function is run again?

Here is a simplified version of our code. In the example below, we would see this error if we ran the **code()** function over again over again in a very short period of time. The **send\_email** function at the end of the **exception** function is where we actually send the email.

```python
GLOBAL_VARIABL = 'email@address.com'

def exception(email):
	if type(email) is list:
		# Add the group email distribution list to the variable
		to.append('group_email@address.com')
	elif type(email) is str:
		# A single email address (string) was supplied to the function; convert 'to' to a list and add the group email distribution list to the variable
		to = [email,'group_email@address.com']
	# Send the email
	send_email('exception error', to)

def code():
	try:
		print(a)
	except:
		exception(GLOBAL_VARIABL)

```

---

<div class="post-metadata">

**Author:** ![ryan.white](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/ryan.white/32/73193_2.png) [@ryan.white](https://forum.inductiveautomation.com/u/ryan.white)\
**Post date:** [December 13, 2024, 8:12pm UTC](https://forum.inductiveautomation.com/t/unexpected-variable-value/99820/2 "2024-12-13T20:12:05Z")

</div>

Your exception function is never initializing `to` to any default value, so you run the risk of forever appending to the previous `to` value until the interpreter instance closes.

Your code should look something more like

```python
def exception(email):
	to = ['group_email@address.com']
	if type(email) is list:
		# Add the group email distribution list to the variable
		to.extend(email)
	elif type(email) is str:
		# A single email address (string) was supplied to the function; convert 'to' to a list and add the group email distribution list to the variable
		to.append(email)
	# Send the email
	send_email('exception error', to)

```

Also, I understand if you omitted the name of the exception for display here but if not you should not be mirroring the same name as a built in function/type.

---

<div class="post-metadata">

**Author:** ![rbachman](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/rbachman/32/43718_2.png) [@rbachman](https://forum.inductiveautomation.com/u/rbachman)\
**Post date:** [December 13, 2024, 8:36pm UTC](https://forum.inductiveautomation.com/t/unexpected-variable-value/99820/3 "2024-12-13T20:36:20Z")

</div>

I apologize. That was actually due to an error in my example code. I was trying to cut out a lot of other error handling in the **exception** function that isn't relevant to this issue.

Here is the _actual_ version of the **exception** function with a few minor edits to remove sensitive email addresses.

```python
def pyException(to=None,object=None,loop=None):
	# 'to' is the email address that should be copied when this function runs.
	# 'object' is the object that caused the exception; this should be 'self' when used on a button
	
	# Import other functions
	import linecache
	import sys
	
	exc_type, exc_obj, tb = sys.exc_info()
	f = tb.tb_frame
	lineno = tb.tb_lineno
	filename = f.f_code.co_filename
	linecache.checkcache(filename)
	line = linecache.getline(filename, lineno, f.f_globals)
	exception = 'EXCEPTION IN ({}, LINE {} "{}"): {}'.format(filename, lineno, line.strip(), exc_obj)
	
		
	try:
		# try to log the user where the error occurred
		user = object.session.props.auth.user.userName
	except:
		# The user variable could not be set, so it will be set to none
		user = None
		
	try:
		# try to log the location where the error occurred
# location = object.view.id
		location = 'Client: ' + str(object.session.props.host) + '; Connected to ' + object.view.id
# location = object.session.getInfo()
	except:
		# The location variable could not be set, so it will be set to none
		location = None

	# Send an email if the to parameter is not null
	if to == None:
		# no one is on the email list; only send it to the ignition inbox
		sendEmail('pyException Error',exception,'ignition@address.com')
	else:
		if type(to) is list:
			# A list of email addresses was supplied to the function; add 'ignition@address.com' to the list 
			to.append('ignition@address.com')
		elif type(to) is str:
			# A single email address (string) was supplied to the function; convert 'to' to a list and add the email address and 'ignition@address.com' to the list
			to = [to,'ignition@address.com']
		# Send the email
		sendEmail('pyException Error',exception,to)
	# Check to see if this error is being generated by a function that could cause a loop
	if loop == None:
		# log the exception to the database
		log(exception, user, location)

```

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [December 13, 2024, 8:43pm UTC](https://forum.inductiveautomation.com/t/unexpected-variable-value/99820/4 "2024-12-13T20:43:42Z")

</div>

> [@rbachman](#):
>
> `to=None,object=None,loop=None`

It's these, default values for function arguments can be a major footgun.

---

<div class="post-metadata">

**Author:** ![rbachman](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/rbachman/32/43718_2.png) [@rbachman](https://forum.inductiveautomation.com/u/rbachman)\
**Post date:** [December 13, 2024, 8:45pm UTC](https://forum.inductiveautomation.com/t/unexpected-variable-value/99820/5 "2024-12-13T20:45:31Z")

</div>

> [@Kevin.Herron](#):
>
> It's these, default values for function arguments can be a major footgun.

Can you elaborate on this? I had already thought of a workaround to my specific issue, but I want to understand what exactly is happening so that we don't have similar issues in other code without realizing it.

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [December 13, 2024, 8:46pm UTC](https://forum.inductiveautomation.com/t/unexpected-variable-value/99820/6 "2024-12-13T20:46:27Z")

</div>

I'm trying to find a good post that explains it and make sure that's really it, but it was the first thing that stood out to me. Hang on...

---

<div class="post-metadata">

**Author:** ![rbachman](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/rbachman/32/43718_2.png) [@rbachman](https://forum.inductiveautomation.com/u/rbachman)\
**Post date:** [December 13, 2024, 8:49pm UTC](https://forum.inductiveautomation.com/t/unexpected-variable-value/99820/7 "2024-12-13T20:49:48Z")

</div>

Is it related to using mutable default values? If so, I may have just found an example: [Use mutable default value as an argument in Python - GeeksforGeeks](https://www.geeksforgeeks.org/use-mutable-default-value-as-an-argument-in-python/)

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [December 13, 2024, 8:49pm UTC](https://forum.inductiveautomation.com/t/unexpected-variable-value/99820/8 "2024-12-13T20:49:54Z")

</div>

`None` is a safe default value, as are primitives and strings, as they are immutable. Collections of any kind are unsafe.

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [December 13, 2024, 8:51pm UTC](https://forum.inductiveautomation.com/t/unexpected-variable-value/99820/9 "2024-12-13T20:51:17Z")

</div>

Yeah, hmm...

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [December 13, 2024, 9:02pm UTC](https://forum.inductiveautomation.com/t/unexpected-variable-value/99820/10 "2024-12-13T21:02:04Z")

</div>

I don't know. I've stared at it and don't see anything.

I'd start with logging the recipients in the `sendEmail` function just to rule out any weird SMTP/outlook problems entirely. If this function logs the duplicate recipients then you know some caller of it is providing multiple.

---

<div class="post-metadata">

**Author:** ![ryan.white](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/ryan.white/32/73193_2.png) [@ryan.white](https://forum.inductiveautomation.com/u/ryan.white)\
**Post date:** [December 13, 2024, 9:47pm UTC](https://forum.inductiveautomation.com/t/unexpected-variable-value/99820/11 "2024-12-13T21:47:23Z")

</div>

Does it have to do with what type the their global variable is?

```python
SOME_GLOBAL_VAL = ["startingString"]

def globalModifier(param1=None):
	if isinstance(param1, str):
		param1 = [param1, "someOtherString"]

	elif isinstance(param1, list):
		param1.append("someOtherString")
	print param1
	return

for x in xrange(3):
	globalModifier(SOME_GLOBAL_VAL)
	print SOME_GLOBAL_VAL

```

nets

```python
['startingString', 'someOtherString']
['startingString', 'someOtherString']
['startingString', 'someOtherString', 'someOtherString']
['startingString', 'someOtherString', 'someOtherString']
['startingString', 'someOtherString', 'someOtherString', 'someOtherString']
['startingString', 'someOtherString', 'someOtherString', 'someOtherString']

```

If the global value is a list, it is modified each time the function is called in the loop, but if it's a string it retains its original value each call.

If whatever is calling their pyException is in a loop, or somehow using the same interpreter instance as previous calls, it could be modifying the global variable's value.

@rbachman what happens if you add `from copy import deepcopy` and then add the line `to = deepcopy(to)` as one of the first lines in the pyException function?

Adding that to my example function prevents it from modifying the global variable's value during the loop.

Additionally, is this pyException being defined in a project library script? If so you should move your import calls outside of your function.

---

<div class="post-metadata">

**Author:** ![michael.flagler](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/michael.flagler/32/26272_2.png) [@michael.flagler](https://forum.inductiveautomation.com/u/michael.flagler)\
**Post date:** [December 13, 2024, 9:58pm UTC](https://forum.inductiveautomation.com/t/unexpected-variable-value/99820/12 "2024-12-13T21:58:52Z")

</div>

I suspect (but could be wrong) it's something to do with what's listed on this page. I don't know if this is python specific or doesn't even apply, but could it be based on how it's called and not the function itself? Look at the highest rated answer here:

> <https://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference>

If that's the case, the better solution would be to use a new list initialized by the function with your group email as the first email, then extend it with the `to` list. (I suspect this may only be happening when passing a list to the function and if that variable `to` list is the same variable and not a different instance, they keep getting appended to the end.)

---

<div class="post-metadata">

**Author:** ![rbachman](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/rbachman/32/43718_2.png) [@rbachman](https://forum.inductiveautomation.com/u/rbachman)\
**Post date:** [March 31, 2025, 5:42pm UTC](https://forum.inductiveautomation.com/t/unexpected-variable-value/99820/13 "2025-03-31T17:42:35Z")

</div>

> [@ryan.white](#):
>
> @rbachman what happens if you add `from copy import deepcopy` and then add the line `to = deepcopy(to)` as one of the first lines in the pyException function?

I haven't had a chance to try this yet (this isn't a huge issue for us), but I am pretty confident that this thread hits on our issue. My plan was to modify the code to check to see if the string/email address is already in the list and then _ **not** _ add it if it is in the list. I could also try this **deepcopy** option.

I'll try to post to this thread against after I try these options.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 31, 2025, 6:05pm UTC](https://forum.inductiveautomation.com/t/unexpected-variable-value/99820/14 "2025-03-31T18:05:52Z")

</div>

jython's `deepcopy` is awful, as it doesn't properly handle map-like and list-like java objects. Consider using my Integration Toolkit's `unQualify()` or `orderedCopy()` functions. The later will also properly handle reference cycles without infinite recursion.
