# \[IGN-5231\] jsonEncode issue

**URL:** <https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603>\
**Category:** Ignition\
**Created:** [March 17, 2021, 10:04pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603 "2021-03-17T22:04:34Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![dandersen](https://avatars.discourse-cdn.com/v4/letter/d/ecb155/32.png) [@dandersen](https://forum.inductiveautomation.com/u/dandersen)\
**Post date:** [March 17, 2021, 10:04pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/1 "2021-03-17T22:04:34Z")

</div>

I must be missing something here. I call a function that returns a dictionary that I then encode into JSON. If I use the dictionary object returned by the function and pass it into the JSON encode, I hit a recursion error. If I create a new variable with the same dictionary, it works fine. Does anyone have any ideas?

```auto
reqParameters = ""
reqRemainingPath = ""

broken = request(reqParameters, reqRemainingPath)
works = {'racks': [{'sampleCount': 0, 'createdAt': 0, 'trayCode': u'asdfasdf', 'rackType': 1}, {'sampleCount': 0, 'createdAt': 0, 'trayCode': u'qwerqwer', 'rackType': 2}, {'sampleCount': 0, 'createdAt': 0, 'trayCode': u'zxcvzxcv', 'rackType': 1}]}
print type(broken)
print type(works)
print broken
print works
system.util.jsonEncode(works)
system.util.jsonEncode(broken)

```

Console Output:

```auto
<type 'dict'>
<type 'dict'>
{'racks': [{'sampleCount': 0, 'createdAt': 0, 'trayCode': u'asdfasdf', 'rackType': 1}, {'sampleCount': 0, 'createdAt': 0, 'trayCode': u'qwerqwer', 'rackType': 2}, {'sampleCount': 0, 'createdAt': 0, 'trayCode': u'zxcvzxcv', 'rackType': 1}]}
{'racks': [{'rackType': 1, 'sampleCount': 0, 'createdAt': 0, 'trayCode': u'asdfasdf'}, {'rackType': 2, 'sampleCount': 0, 'createdAt': 0, 'trayCode': u'qwerqwer'}, {'rackType': 1, 'sampleCount': 0, 'createdAt': 0, 'trayCode': u'zxcvzxcv'}]}
u'{"racks":[{"sampleCount":0,"createdAt":0,"trayCode":"asdfasdf","rackType":1},{"sampleCount":0,"createdAt":0,"trayCode":"qwerqwer","rackType":2},{"sampleCount":0,"createdAt":0,"trayCode":"zxcvzxcv","rackType":1}]}'
Traceback (most recent call last):
  File "<buffer>", line 34, in <module>
RuntimeError: maximum recursion depth exceeded

```

---

<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:** [March 17, 2021, 10:31pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/2 "2021-03-17T22:31:16Z")

</div>

What are the types of the objects _in_ `broken`? Any chance they’re qualified values or quality codes?

---

<div class="post-metadata">

**Author:** ![dandersen](https://avatars.discourse-cdn.com/v4/letter/d/ecb155/32.png) [@dandersen](https://forum.inductiveautomation.com/u/dandersen)\
**Post date:** [March 18, 2021, 2:15pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/3 "2021-03-18T14:15:57Z")

</div>

Broken is just a dictionary with a list of dictionaries. Each dictionary in that list is just integers.

I run this code against `broken` and I get all integers.

```auto
for key in broken:
	print type(broken[key])
	print broken[key]
	for listDic in broken[key]:
		for key2 in listDic:
			print type(listDic[key2])

```

```auto
<type 'list'>
[{'sampleCount': 3, 'createdAt': 2, 'trayCode': 1, 'rackType': 4}, {'sampleCount': 3, 'createdAt': 2, 'trayCode': 1, 'rackType': 4}, {'sampleCount': 3, 'createdAt': 2, 'trayCode': 1, 'rackType': 4}]
<type 'int'>
<type 'int'>
<type 'int'>
<type 'int'>
<type 'int'>
<type 'int'>
<type 'int'>
<type 'int'>
<type 'int'>
<type 'int'>
<type 'int'>
<type 'int'>

```

---

<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:** [March 18, 2021, 3:49pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/4 "2021-03-18T15:49:43Z")

</div>

Does `system.util.jsonEncode(dict(broken))` also fail?  
It’s gotta be something about the scripting function returning a weird object, but without your code it’s hard to replicate.

---

<div class="post-metadata">

**Author:** ![dandersen](https://avatars.discourse-cdn.com/v4/letter/d/ecb155/32.png) [@dandersen](https://forum.inductiveautomation.com/u/dandersen)\
**Post date:** [March 18, 2021, 3:52pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/5 "2021-03-18T15:52:03Z")

</div>

Yes that type cast also fails. I’ll post the code in anther comment here.

---

<div class="post-metadata">

**Author:** ![dandersen](https://avatars.discourse-cdn.com/v4/letter/d/ecb155/32.png) [@dandersen](https://forum.inductiveautomation.com/u/dandersen)\
**Post date:** [March 18, 2021, 3:55pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/6 "2021-03-18T15:55:03Z")

</div>

Test code run from Script Console to get debug output

```auto
from project.app.res import vial, rack
from project.app import logger

def request(parameters, remainingPath):
	if remainingPath == "":
		# get all racks/vials
		logger.apiLog.debug("Get All Racks and Vials")
		return getAllInventory()
		
		
def getAllInventory():
	rackList = []
	inventory = {'racks':[]}
	# get a all racks in inventory
	rackDS = system.db.runNamedQuery("inventory/getAllRacks")
	if rackDS.getRowCount():
		# we have racks in inventory. get all vials for each rack.
		trayDS = system.dataset.toPyDataSet(rackDS)
		for tray in trayDS:
			rackList.append(rack(tray). __dict__ )
	inventory['racks'] = rackList
	return inventory

reqParameters = ""
reqRemainingPath = ""

broken = request(reqParameters, reqRemainingPath)
works = {'racks': [{'sampleCount': 3, 'createdAt': 2, 'trayCode': 1, 'rackType': 4}, {'sampleCount': 3, 'createdAt': 2, 'trayCode': 1, 'rackType': 4}, {'sampleCount': 3, 'createdAt': 2, 'trayCode': 1, 'rackType': 4}]}
print type(broken)
print type(works)
print broken
print works
system.util.jsonEncode(works)
system.util.jsonEncode(dict(broken))

```

Here is Class `rack` from `project.app.res`

```auto
class rack(object):
	def __init__ (self, dbRecord):
		self.trayCode = dbRecord['trayCode']
		self.createdAt = dbRecord['createdAt']
		self.sampleCount = dbRecord['sampleCount']
		self.rackType = dbRecord['rackType']
		self.location = {'carouselCode':dbRecord['carouselCode']}
		self.location['col'] = dbRecord['col']
		self.location['row'] = dbRecord['row']

```

---

<div class="post-metadata">

**Author:** ![chasondeshotel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/chasondeshotel/32/20032_2.png) [@chasondeshotel](https://forum.inductiveautomation.com/u/chasondeshotel)\
**Post date:** [March 18, 2021, 4:38pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/7 "2021-03-18T16:38:09Z")

</div>

This doesn’t answer the question but there’s some things I would do along the path of trying to fix it

```auto
# these will be cached by Ignition, always use the long form of method calls / constructors
#from project.app.res import vial, rack
#from project.app import logger

# set defaults
def request(parameters = None, remainingPath = None):
	if remainingPath:
		# get all racks/vials
		project.app.logger.apiLog.debug("Get All Racks and Vials")
		return getAllInventory()
		
		
def getAllInventory():
	rackList = []
	inventory = {}
	# get a all racks in inventory
	rackDS = system.db.runNamedQuery("inventory/getAllRacks")
	if rackDS.getRowCount():
		# we have racks in inventory. get all vials for each rack.
		#
		# you are turning rack dataset into a py dataset but it's the same data
		# wouldn't this be rackPyDS?
		# 
		trayDS = system.dataset.toPyDataSet(rackDS)
		for tray in trayDS:
			rackList.append(rack(tray). __dict__ )
	inventory['racks'] = rackList
	return inventory

broken = request()
works = {'racks': [{'sampleCount': 3, 'createdAt': 2, 'trayCode': 1, 'rackType': 4}, {'sampleCount': 3, 'createdAt': 2, 'trayCode': 1, 'rackType': 4}, {'sampleCount': 3, 'createdAt': 2, 'trayCode': 1, 'rackType': 4}]}

import pprint
pprint.pprint(broken)

```

---

<div class="post-metadata">

**Author:** ![chasondeshotel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/chasondeshotel/32/20032_2.png) [@chasondeshotel](https://forum.inductiveautomation.com/u/chasondeshotel)\
**Post date:** [March 18, 2021, 4:47pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/9 "2021-03-18T16:47:08Z")

</div>

```auto
def getAllInventory():
	rackList = []
	inventory = {}
	# get a all racks in inventory
	# toPyDataSet will return None if the named query comes back empty
	rackPyDS = system.dataset.toPyDataSet(system.db.runNamedQuery("inventory/getAllRacks"))
	# I don't know how you want to get to trays, but this is still rackPyDS
	#trayDS = system.dataset.toPyDataSet(rackDS)
	if rackPyDS:
		inventory['racks'] = [project.app.res.Rack(rack). __dict__ for rack in rackPyDS]
		return inventory

```

edit:

`rack` is referring to the `rack` class not `rackDS`. By convention classes should be uppercase… `Rack`. That’s confusing.

You should also use the long form to instantiate that object: `project.app.res.Rack(tray)`

Why are you instantiating objects to get their dictionary and not passing the actual objects around?

---

<div class="post-metadata">

**Author:** ![dandersen](https://avatars.discourse-cdn.com/v4/letter/d/ecb155/32.png) [@dandersen](https://forum.inductiveautomation.com/u/dandersen)\
**Post date:** [March 18, 2021, 5:07pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/10 "2021-03-18T17:07:46Z")

</div>

I create an instance of an object to be able to use its ` __dict__ ` as I need the dictionary representation of that object so it can be encoded in JSON. I realize I could build up the dictionary my self but then as I add more to the class, I would have to update the code that loops over the object.

I’m a little confused about your solution. I don’t have any issue with `getAllInventory()` method. That works correctly. The issue is when I try to encode the dictionary from that method. If I pass it directly into `system.util.jsonEncode()`, it fails, where if I create the same exact dictionary, it works. I ran your modified code and I get the same error.

---

<div class="post-metadata">

**Author:** ![chasondeshotel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/chasondeshotel/32/20032_2.png) [@chasondeshotel](https://forum.inductiveautomation.com/u/chasondeshotel)\
**Post date:** [March 18, 2021, 5:18pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/11 "2021-03-18T17:18:10Z")

</div>

So my remaining question is what does each rack in rackPyDS look like because this is going to have to change:

```auto
inventory['racks'] = [project.app.res.Rack(rack). __dict__ for rack in rackPyDS]

```

In response to your edit:

There’s obvious issues with the code. Not entirely sure where your issue lies but if we solve the ones we see then maybe we’ll fix it on the way. If that doesn’t fix it at least we get a concise bug report

Granted I should have spent more time proofreading but the lowercase object instantiation with a name two characters away from a variable used two lines before threw me for a loop 😅

---

<div class="post-metadata">

**Author:** ![dandersen](https://avatars.discourse-cdn.com/v4/letter/d/ecb155/32.png) [@dandersen](https://forum.inductiveautomation.com/u/dandersen)\
**Post date:** [March 18, 2021, 5:24pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/12 "2021-03-18T17:24:35Z")

</div>

I don't think I understand the question below.

> So my remaining question is what does each rack in rackPyDS look like because this is going to have to change:

---

<div class="post-metadata">

**Author:** ![chasondeshotel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/chasondeshotel/32/20032_2.png) [@chasondeshotel](https://forum.inductiveautomation.com/u/chasondeshotel)\
**Post date:** [March 18, 2021, 5:30pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/13 "2021-03-18T17:30:26Z")

</div>

I’m presuming racks and trays are different things and racks contain trays?

because this

`rackDS = system.db.runNamedQuery("inventory/getAllRacks")`

and this

`trayDS = system.dataset.toPyDataSet(rackDS)`

are the same data except one is in `dataSet` form and one is in `pyDataSet` form.

So either we need to get trays from racks or those variable names are muddying the water

If we need to get trays from racks, I would like to know what the data for one rack looks like

---

<div class="post-metadata">

**Author:** ![dandersen](https://avatars.discourse-cdn.com/v4/letter/d/ecb155/32.png) [@dandersen](https://forum.inductiveautomation.com/u/dandersen)\
**Post date:** [March 18, 2021, 5:32pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/14 "2021-03-18T17:32:20Z")

</div>

Ah I see. Racks and Trays are the exact same thing. We just changed the name for debug purposes to make sure it wasn’t causing any issues. The same corrected code is below that includes your suggested changes.

```auto
def getAllInventory():
	rackList = []
	inventory = {}
	# get a all racks in inventory
	rackDS = system.db.runNamedQuery("inventory/getAllRacks")
	if rackDS.getRowCount():
		# we have racks in inventory. get all vials for each rack.
		rackPyDS = system.dataset.toPyDataSet(rackDS)
		for rack in rackPyDS:
			rackList.append(project.app.res.Rack(rack). __dict__ )
	inventory['racks'] = rackList
	return inventory

```

---

<div class="post-metadata">

**Author:** ![chasondeshotel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/chasondeshotel/32/20032_2.png) [@chasondeshotel](https://forum.inductiveautomation.com/u/chasondeshotel)\
**Post date:** [March 18, 2021, 5:41pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/15 "2021-03-18T17:41:59Z")

</div>

Aha. Gotcha. I thought for sure you going one level deeper but indexing the parent every time. I was so excited I found the solution lol

I’m going to make a table and named query to see if I can duplicate this

I almost feel bad about being a total distraction but getting that class name uppercased was well worth the effort 😁 (oh, and the long form calls, that will bite you eventually)

---

<div class="post-metadata">

**Author:** ![dandersen](https://avatars.discourse-cdn.com/v4/letter/d/ecb155/32.png) [@dandersen](https://forum.inductiveautomation.com/u/dandersen)\
**Post date:** [March 18, 2021, 5:44pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/16 "2021-03-18T17:44:52Z")

</div>

No worries! I appreciate the help and pointers. As much as I like to one line code, this is going to be maintained by some folks that aren’t super Python savvy so that is why I’m really spelling everything out and not condensing the loops and such.

Here is what the output of that query looks like.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/7/a/7ae38f9d9b6f03d83f080863ba18563e780b6216.png)

Edit:  
This is in Ignition 7.9.14 so I’m wondering if its an issue with how Jython 2.5?

---

<div class="post-metadata">

**Author:** ![chasondeshotel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/chasondeshotel/32/20032_2.png) [@chasondeshotel](https://forum.inductiveautomation.com/u/chasondeshotel)\
**Post date:** [March 18, 2021, 5:51pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/17 "2021-03-18T17:51:50Z")

</div>

Yeah that's totally fair. I do think

```auto
rackPyDS = system.dataset.toPyDataSet(system.db.runNamedQuery("inventory/getAllRacks"))
if rackPyDS:

```

is easier because it reads super Englishy and you don't have to carry variables in your head but I totally get that plenty of folks get lost at comprehensions

> This is in Ignition 7.9.14 so I’m wondering if its an issue with how Jython 2.5?

I only have access to 8.1.15 at the moment. Maybe we can narrow it down at least. Thanks for the screenshot. Working on this now

edit in case anyone else wants to take a stab:

```auto
create table racks (
	carouselCode char(1)
	, col int
	, [row] int
	, createdAt datetime null
	, trayCode nvarchar(20)
	, sampleCount int
	, rackType int
)

insert into backup_getAllRacks (
	carouselCode, col, [row], createdAt, trayCode, sampleCount, rackType
	)
values
	('A',1,1,NULL,'asdfasdf',NULL,1)
	, ('A',1,2,NULL,'qwerqwer',NULL,2)
	, ('A',1,3,NULL,'zxcvzxcv',NULL,1)

```

---

<div class="post-metadata">

**Author:** ![WillMT10](https://avatars.discourse-cdn.com/v4/letter/w/7feea3/32.png) [@WillMT10](https://forum.inductiveautomation.com/u/WillMT10)\
**Post date:** [March 18, 2021, 6:26pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/18 "2021-03-18T18:26:28Z")

</div>

I might be missing something, but what you have in the printout for `broken` doesn’t match what your named query is showing. Specifically the NULL values for `createdAt` and `sampleCount`, and I don’t see anything that is handling those NULLs in your scripts

---

<div class="post-metadata">

**Author:** ![dandersen](https://avatars.discourse-cdn.com/v4/letter/d/ecb155/32.png) [@dandersen](https://forum.inductiveautomation.com/u/dandersen)\
**Post date:** [March 18, 2021, 6:32pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/19 "2021-03-18T18:32:45Z")

</div>

The NULLs in the DB just get converted to a None type. When `system.util.jsonEncode()` comes across a None Type, it just puts “null” into the JSON output.

---

<div class="post-metadata">

**Author:** ![WillMT10](https://avatars.discourse-cdn.com/v4/letter/w/7feea3/32.png) [@WillMT10](https://forum.inductiveautomation.com/u/WillMT10)\
**Post date:** [March 18, 2021, 6:47pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/20 "2021-03-18T18:47:12Z")

</div>

These are getting converted to integers prior to the `jsonEncode()`…maybe a default behavior of ` __dict__ ` that I’m not aware of. One thing I noticed is that the type returned from ` __dict__ ` is not actually a true dict, it is apparently a `dictproxy`, so I’m not sure if that could cause some bad behaviors.

---

<div class="post-metadata">

**Author:** ![chasondeshotel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/chasondeshotel/32/20032_2.png) [@chasondeshotel](https://forum.inductiveautomation.com/u/chasondeshotel)\
**Post date:** [March 18, 2021, 6:47pm UTC](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603/21 "2021-03-18T18:47:34Z")

</div>

@WillMT10 I noticed that too. I’m quite sure (this time) that this is the actual issue at hand:

```auto
system.util.jsonEncode(Rack('foo'). __dict__ )

```

[Next page](https://forum.inductiveautomation.com/t/ign-5231-jsonencode-issue/44603.md?page=2)
