# Issues when using system.util.invokeAsynchronous() I get a 'NoneType' object is not callable error

**URL:** <https://forum.inductiveautomation.com/t/issues-when-using-system-util-invokeasynchronous-i-get-a-nonetype-object-is-not-callable-error/97022>\
**Category:** Ignition\
**Tags:** perspective, scripting\
**Created:** [October 9, 2024, 2:06pm UTC](https://forum.inductiveautomation.com/t/issues-when-using-system-util-invokeasynchronous-i-get-a-nonetype-object-is-not-callable-error/97022 "2024-10-09T14:06:44Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![CSag](https://avatars.discourse-cdn.com/v4/letter/c/9dc877/32.png) [@CSag](https://forum.inductiveautomation.com/u/CSag)\
**Post date:** [October 9, 2024, 2:06pm UTC](https://forum.inductiveautomation.com/t/issues-when-using-system-util-invokeasynchronous-i-get-a-nonetype-object-is-not-callable-error/97022/1 "2024-10-09T14:06:44Z")

</div>

When using _**system.util.invokeAsynchronous()**_ I keep receiving this error:

**Message:**

> Error running function from `fpmi.system.invokeAsynchronous`

**Details:**

> TypeError: 'NoneType' object is not callable
> 
> at org.python.core.Py.TypeError(Py.java:236)  
> at org.python.core.PyObject. **call** (PyObject.java:396)  
> at com.inductiveautomation.ignition.common.script.ScriptManager.runFunction(ScriptManager.java:847)  
> at com.inductiveautomation.ignition.client.script.DesignerSystemUtilities.lambda$\_invokeAsyncImpl$1(DesignerSystemUtilities.java:140)  
> at java.base/java.lang.Thread.run(Unknown Source)
> 
> Ignition v8.1.32 (b2023091211)  
> Java: Azul Systems, Inc. 11.0.18

After running this code:

```python
path = "Select Query"
tagPaths = "[Queue]Queue"
sequenced = system.db.runNamedQuery(path)
updateBlockQueue = system.dataset.toDataSet(sequenced)
system.tag.writeBlocking(tagPaths, updateQueue)

tagData = system.tag.readBlocking(tagPaths)[0].value
pyTagData = system.dataset.toPyDataSet(tagData)

updates = []

def updateSize(index, row, updates):
	config = system.db.runNamedQuery("Select Config",{"WO": row[1]})
	engineSize = system.db.runNamedQuery("Select Size", {"configCode": config[0][0]})
	updates.append((index, {"SIZE":Size[0][0]}))
	
def applyUpdates(tagPaths, tagData, update):
	for index, update in updates:
		tagData = system.dataset.updateRow(tagData, index, update)
	system.tag.writeBlocking([tagPaths], [tagData])

def runUpdates():
	a = system.date.now()
	for index, row in enumerate(pyTagData):
		system.util.invokeAsynchronous(updateSize(index, row, updates))

	system.util.invokeAsynchronous(applyUpdates(tagPaths, tagData, update))
	b = system.date.now()
	total = system.date.secondsBetween(a, b)
	print(total)

runUpdates()

```

This will execute with the result I need, and all of the data is correct, but the error mentioned is still being posted. I do not know why.

**I am running this in the Script Console for testing purposes.**

---

<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:** [October 9, 2024, 2:13pm UTC](https://forum.inductiveautomation.com/t/issues-when-using-system-util-invokeasynchronous-i-get-a-nonetype-object-is-not-callable-error/97022/2 "2024-10-09T14:13:08Z")

</div>

All of your threads will run concurrently. `system.util.invokeAsynchronous()` doesn't wait for that task to complete. (That's the whole point of it.)

That any updates are completed by `updateSize()` before `applyUpdates()` accesses the list is pure chance.

Your non-UI operations, including loops through the data, should be in a single function for asynchronous execution.

(You should move this whole task to a project library script.)

Consider also **not** using `system.dataset.updateRow()` if you are completely replacing the dataset. Just build a fresh dataset from scratch--it's faster. If you need control over column types, use the `DatasetBuilder` class instead of `system.util.toDataSet()`.

---

<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:** [October 9, 2024, 2:18pm UTC](https://forum.inductiveautomation.com/t/issues-when-using-system-util-invokeasynchronous-i-get-a-nonetype-object-is-not-callable-error/97022/3 "2024-10-09T14:18:32Z")

</div>

> [@CSag](#):
>
> ```python
> system.util.invokeAsynchronous(updateSize(index, row, updates))
> 
> ```

While everything Phil said is true, you're also just calling invokeAsynchronous fundamentally wrong.

You need to pass a callable _reference_ to your function. What you're currently doing is _running your function_, blocking the invoking thread, and then returning the result (None) to invokeAsynchronous, which is why it's failing.

You need to use a syntax like this:

```python
system.util.invokeAsynchronous(updateSize, args = [index, row, updates])

```

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [October 9, 2024, 2:19pm UTC](https://forum.inductiveautomation.com/t/issues-when-using-system-util-invokeasynchronous-i-get-a-nonetype-object-is-not-callable-error/97022/4 "2024-10-09T14:19:32Z")

</div>

> [@CSag](#):
>
> `system.util.invokeAsynchronous(updateSize(index, row, updates))`

This looks wrong to me. I believe it should just be the function name, without the signature. If you need to pass parameters into the function then they ~~should~~ can be done as default parameter values, or using the args list. The `NoneType` is probably coming from that fact.

Aside from all of the other things that Phil mentioned about this.

EDIT: Ninjad by Paul!!

---

<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:** [October 9, 2024, 2:19pm UTC](https://forum.inductiveautomation.com/t/issues-when-using-system-util-invokeasynchronous-i-get-a-nonetype-object-is-not-callable-error/97022/5 "2024-10-09T14:19:37Z")

</div>

> [@paul-griffith](#):
>
> returning the result (None) to invokeAsynchronous

Hah! I was blinded by the other flaws.

---

<div class="post-metadata">

**Author:** ![CSag](https://avatars.discourse-cdn.com/v4/letter/c/9dc877/32.png) [@CSag](https://forum.inductiveautomation.com/u/CSag)\
**Post date:** [October 9, 2024, 2:24pm UTC](https://forum.inductiveautomation.com/t/issues-when-using-system-util-invokeasynchronous-i-get-a-nonetype-object-is-not-callable-error/97022/6 "2024-10-09T14:24:11Z")

</div>

I have done this.  
The result is it may not be running updateSize() correctly or at all.  
I added print() statements to this function with no result of the print statements running.

I have no errors, yes, but none of the data is updating as it did before.

---

<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:** [October 9, 2024, 2:25pm UTC](https://forum.inductiveautomation.com/t/issues-when-using-system-util-invokeasynchronous-i-get-a-nonetype-object-is-not-callable-error/97022/7 "2024-10-09T14:25:28Z")

</div>

That doesn't really mean anything:

> [@Event Configuration Print Out to debug](https://forum.inductiveautomation.com/t/event-configuration-print-out-to-debug/60091/5):
>
> It’s complicated slight_smile Starting from most local to least… In the script console, print will log directly to the output buffer on the right hand side. system.util.getLogger() will log to the named ‘Output Console’ Designer window. Bonus: A script invoked from here using system.util.invokeAsync will print to the regular output console, not the buffer on the right hand side. Anywhere else in the designer (except Perspective), print and system.util.getLogger will log to the ‘Out…

Post your updated code.

---

<div class="post-metadata">

**Author:** ![CSag](https://avatars.discourse-cdn.com/v4/letter/c/9dc877/32.png) [@CSag](https://forum.inductiveautomation.com/u/CSag)\
**Post date:** [October 9, 2024, 2:56pm UTC](https://forum.inductiveautomation.com/t/issues-when-using-system-util-invokeasynchronous-i-get-a-nonetype-object-is-not-callable-error/97022/8 "2024-10-09T14:56:32Z")

</div>

Here is the updated code that will not return errors, but will not result in updating the datset/memory tag.

```python
def runUpdates():
	a = system.date.now()
	for index, row in enumerate(pyTagData):
		system.util.invokeAsynchronous(updateSize, args =[index, row, updates])

	system.util.invokeAsynchronous(applyUpdates, args =[tagPaths, tagData, update])
	b = system.date.now()
	total = system.date.secondsBetween(a, b)
	print(total)

```

From what I am hearing it seems like I may be using this incorrectly, so this is what I was aiming for and why I started using _**system.util.invokeAsynchronous()**_.

My end goal is to pull data from a database from different tables and display that data on a table in a perspective view. I originally consolidated all of this to an SQL query, but the joins required to obtain the data increase the execution time to an unreasonable length (upgrading the DB's resources is not optional). By executing parts of the query individually and using ignition to as a "middleman" with a form of multi-threading I was able to reduce this time significantly (more than half).

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [October 9, 2024, 3:20pm UTC](https://forum.inductiveautomation.com/t/issues-when-using-system-util-invokeasynchronous-i-get-a-nonetype-object-is-not-callable-error/97022/9 "2024-10-09T15:20:38Z")

</div>

> [@CSag](#):
>
> but the joins required to obtain the data increase the execution time to an unreasonable length

What is an "unreasonable length"?

I would be shocked if a python script asynchronous or otherwise, is going to be more efficient at building a record set of data than a database engine. That is the express purpose that databases are made to handle.

Also, see Phil's original response. You are definitely not doing this correctly. There should be a single call to `invokeAsynchronous`. Right now, you are running thread in parallel that that require context from other threads, and relying purely on chance that the context is valid.

Also, to make matters worse you are using the `update` variable outside of the scope in which it is created. Confusingly, you are sending it to the function in which it is created? I think that the `update` variable in the function def for `applyUpdates` should actually be updates? Either way, there are problems in you script.

---

<div class="post-metadata">

**Author:** ![CSag](https://avatars.discourse-cdn.com/v4/letter/c/9dc877/32.png) [@CSag](https://forum.inductiveautomation.com/u/CSag)\
**Post date:** [October 9, 2024, 3:59pm UTC](https://forum.inductiveautomation.com/t/issues-when-using-system-util-invokeasynchronous-i-get-a-nonetype-object-is-not-callable-error/97022/10 "2024-10-09T15:59:49Z")

</div>

4+min This data is constantly changing every 73 or so seconds. There are 4 tables with large amounts of data to filter 10mil+ records. I agree with you in that the database should not be slower, this is only my observation and what I have been allowed to use.

I see the flaw that Phil pointed out and I am going to correct that. I suspect since I was using `invokeAsynchronous` incorrectly, it was showing the data in the end result as expected.

Regarding the `update` variable, passing `update` to `applyUpdates()` was a typo in an older iteration and has since been removed, still netting the same result where no data is being updated.

I will take all of this in consideration and work on revising my code. thank you everyone.

---

<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:** [October 9, 2024, 5:57pm UTC](https://forum.inductiveautomation.com/t/issues-when-using-system-util-invokeasynchronous-i-get-a-nonetype-object-is-not-callable-error/97022/11 "2024-10-09T17:57:30Z")

</div>

It's a bit awkward, but here's a proof-of-concept of using Java's `CompletableFuture` API to automatically run multiple operations on an async thread pool (managed by Java in this case), wait for all those operations to complete, and then do some work with all their results on another async thread:

```python
from java.util.concurrent import CompletableFuture
from functools import partial

from java.util.function import Consumer, Supplier

# Adapts a Python function to act as a Java "Consumer" functional interface
# Works when called directly or as a decorator with @ syntax
class java_consumer(Consumer):
	def __init__ (self, func):
		self._func = func
	def accept(self, t):
		self._func(t)

# Adapts a Python function to act as a Java "Supplier" functional interface
class java_supplier(Supplier):
	def __init__ (self, func):
		self._func = func
	def get(self):
		return self._func()

# Note: For efficiency, the above classes should live in your project library

# Mock update function that just blocks for a fixed delay
# Note: In real code, never import inside a function definition
def updateSize(row):
	from time import sleep
	sleep(2)
	return {"SIZE": row}

# Modified applyUpdates function will be guaranteed to get all updates in order, after they have all been completed
def applyUpdates(futures):
	for i, future in enumerate(futures):
		print i, future.get()

def runUpdates():
	# Just some mock data to stick to the general structure of the existing code
	tagData = system.dataset.toDataSet(["a", "b"], [[1, 2], [2, 3], [3, 4]])
	pyTagData = system.dataset.toPyDataSet(tagData)
	
	futures = []
	for row in pyTagData:
		# Some antics here to adapt types and wrap up default arguments
		supplier = java_supplier(partial(updateSize, row))
		# supplyAsync is a static method that will use Java's built in ForkJoinPool thread pool
		futures.append(CompletableFuture.supplyAsync(supplier))

	# Again, some coercion is required to get types happy
	callback = java_consumer(lambda r: applyUpdates(start, futures))

	# allOf returns a new future that's a "composite" of the inputs - so when all of the input futures are done
	# the callback will be invoked, itself on an async thread
	CompletableFuture.allOf(futures).thenAcceptAsync(callback)

runUpdates()

```

---

<div class="post-metadata">

**Author:** ![francisco.salinas](https://avatars.discourse-cdn.com/v4/letter/f/ce73a5/32.png) [@francisco.salinas](https://forum.inductiveautomation.com/u/francisco.salinas)\
**Post date:** [December 9, 2025, 3:58pm UTC](https://forum.inductiveautomation.com/t/issues-when-using-system-util-invokeasynchronous-i-get-a-nonetype-object-is-not-callable-error/97022/12 "2025-12-09T15:58:41Z")

</div>

The following is @paul-griffith's answer without a callback so `futures` can be accessed on the main thread and allow for simpler error handling:

```python
from java.util.concurrent import CompletableFuture
from java.util.function import Consumer, Supplier
from functools import partial
from time import sleep

# Adapts a Python function to act as a Java "Consumer" functional interface
# Works when called directly or as a decorator with @ syntax
def java_consumer(func):
	class PythonConsumer(Consumer):
		def accept(self, t):
			func(t)
	return PythonConsumer()

# Adapts a Python function to act as a Java "Supplier" functional interface
def java_supplier(func):
	class PythonSupplier(Supplier):
		def get(self):
			return func()
	return PythonSupplier()

# Mock update function that just blocks for a fixed delay
def updateSize(row):
	sleep(2)
	return {"SIZE": row}
	

def runUpdates():
	# Just some mock data to stick to the general structure of the existing code
	tagData = system.dataset.toDataSet(["a", "b"], [[1, 2], [2, 3], [3, 4]])
	pyTagData = system.dataset.toPyDataSet(tagData)
	
	futures = []
	for row in pyTagData:
		# Some antics here to adapt types and wrap up default arguments
		supplier = java_supplier(partial(updateSize, row))
		# supplyAsync is a static method that will use Java's built in ForkJoinPool thread pool
		futures.append(CompletableFuture.supplyAsync(supplier))

	# the callback is no longer needed with the use of .get()
	CompletableFuture.allOf(futures).get()

	for i, future in enumerate(futures):
		print i, future.get()

runUpdates()

```

---

<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 9, 2025, 4:17pm UTC](https://forum.inductiveautomation.com/t/issues-when-using-system-util-invokeasynchronous-i-get-a-nonetype-object-is-not-callable-error/97022/13 "2025-12-09T16:17:38Z")

</div>

I'm struggling to understand, Francisco, why you repeated Paul's answer? I don't see any new information in your comment. What did I miss?

---

<div class="post-metadata">

**Author:** ![francisco.salinas](https://avatars.discourse-cdn.com/v4/letter/f/ce73a5/32.png) [@francisco.salinas](https://forum.inductiveautomation.com/u/francisco.salinas)\
**Post date:** [December 9, 2025, 4:31pm UTC](https://forum.inductiveautomation.com/t/issues-when-using-system-util-invokeasynchronous-i-get-a-nonetype-object-is-not-callable-error/97022/14 "2025-12-09T16:31:31Z")

</div>

The difference is in the last 4 lines.

---

<div class="post-metadata">

**Author:** ![code\_skin](https://avatars.discourse-cdn.com/v4/letter/c/43a26b/32.png) [@code\_skin](https://forum.inductiveautomation.com/u/code_skin)\
**Post date:** [December 9, 2025, 4:34pm UTC](https://forum.inductiveautomation.com/t/issues-when-using-system-util-invokeasynchronous-i-get-a-nonetype-object-is-not-callable-error/97022/15 "2025-12-09T16:34:17Z")

</div>

You’re also missing the import for CompletableFuture.

---

<div class="post-metadata">

**Author:** ![francisco.salinas](https://avatars.discourse-cdn.com/v4/letter/f/ce73a5/32.png) [@francisco.salinas](https://forum.inductiveautomation.com/u/francisco.salinas)\
**Post date:** [December 9, 2025, 4:35pm UTC](https://forum.inductiveautomation.com/t/issues-when-using-system-util-invokeasynchronous-i-get-a-nonetype-object-is-not-callable-error/97022/16 "2025-12-09T16:35:10Z")

</div>

Thank you. Edited that just now.

---

<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 9, 2025, 5:01pm UTC](https://forum.inductiveautomation.com/t/issues-when-using-system-util-invokeasynchronous-i-get-a-nonetype-object-is-not-callable-error/97022/17 "2025-12-09T17:01:34Z")

</div>

Keep in mind that Paul's code is just a proof of concept that needs cleanup for general deployment. In particular:

- The code shown is formatted as if embedded in an event script, where the bulk of it should be factored out into a project library script, so it can be defined once and re-used. Imports should only be in project library scripts, and always **outside** any function or class definitions.

- The Consumer and Supplier jython wrappers would be more efficient if defined with a constructor, instead of defining the class itself inside a closure. When done via closure, the class will never get the chance to be fully optimized by the JVM under heavy usage. I recommend the following (in a library script):

```python
from java.util.function import Consumer, Supplier

# Adapts a Python function to act as a Java "Consumer" functional interface
# Works when called directly or as a decorator with @ syntax
class java_consumer(Consumer):
	def __init__ (self, func):
		self._func = func
	def accept(self, t):
		self._func(t)

# Adapts a Python function to act as a Java "Supplier" functional interface
class java_supplier(Supplier):
	def __init__ (self, func):
		self._func = func
	def get(self):
		return self._func()

```
