Perspective: Error creating 'expr-struct' binding on property "Dictionary size changed during iteration"

This error came across the logs, at the moment I'm not sure how frequent it may be. Running Ignition 8.1.50.

It doesn't seem like this is directly caused by the script transform, the script transform is simply accessing keys on the expression structure binding result. Has anyone encountered a similar error?

ignition  | jvm 1    | 2026/04/13 15:49:42 | W [p.ViewModel                   ] [15:49:42.014]: Error creating 'expr-struct' binding on property 'custom.{prop}' project-name={project}, view={view}@C$0:2$0:0$0:0$0:0:1$0:0[4]$0:0$0:0:0
ignition  | jvm 1    | 2026/04/13 15:49:42 | org.python.core.PyException: RuntimeError: dictionary changed size during iteration
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at org.python.core.Py.RuntimeError(Py.java:155)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at org.python.core.AbstractDict$AbstractDictIter.check(AbstractDict.java:89)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at org.python.core.PyStringMap$StringMapKeysIter.__iternext__(PyStringMap.java:743)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at org.python.core.WrappedIterIterator.hasNext(WrappedIterIterator.java:23)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at com.inductiveautomation.ignition.common.script.ScriptManager.createLocalsMap(ScriptManager.java:699)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at com.inductiveautomation.perspective.gateway.binding.transforms.script.ScriptTransform.createLocalsMap(ScriptTransform.java:101)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at com.inductiveautomation.perspective.gateway.binding.transforms.script.ScriptTransform.compile(ScriptTransform.java:68)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at com.inductiveautomation.perspective.gateway.binding.transforms.script.ScriptTransform.<init>(ScriptTransform.java:50)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at com.inductiveautomation.perspective.gateway.binding.BindingRegistryImpl.createTransform(BindingRegistryImpl.java:118)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at com.inductiveautomation.perspective.gateway.model.AbstractBindingHarness.<init>(AbstractBindingHarness.java:77)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at com.inductiveautomation.perspective.gateway.model.ElementBindingHarness.<init>(ElementBindingHarness.java:23)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at com.inductiveautomation.perspective.gateway.model.ElementBindingHarness.lambda$newFactory$0(ElementBindingHarness.java:28)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at com.inductiveautomation.perspective.gateway.model.BindingCollection.create(BindingCollection.java:62)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at com.inductiveautomation.perspective.gateway.model.ViewModel.<init>(ViewModel.java:118)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at com.inductiveautomation.perspective.gateway.session.SecuredPerspectiveProjectSession.createViewModel(SecuredPerspectiveProjectSession.java:446)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at com.inductiveautomation.perspective.gateway.session.PerspectiveProjectSession.createViewModel(PerspectiveProjectSession.java:106)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at com.inductiveautomation.perspective.gateway.model.PageModel$Handlers.lambda$startView$25(PageModel.java:1153)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at com.inductiveautomation.perspective.gateway.api.LoggingContext.mdc(LoggingContext.java:54)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at com.inductiveautomation.perspective.gateway.model.PageModel$Handlers.lambda$startView$26(PageModel.java:1143)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at java.base/java.util.concurrent.CompletableFuture$UniAccept.tryFire(Unknown Source)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at java.base/java.util.concurrent.CompletableFuture$Completion.run(Unknown Source)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at com.inductiveautomation.ignition.common.util.TimedRunnable.run(TimedRunnable.java:21)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at com.inductiveautomation.ignition.common.util.ExecutionQueue$PollAndExecute.run(ExecutionQueue.java:239)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(UnknownSource)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
ignition  | jvm 1    | 2026/04/13 15:49:42 |    at java.base/java.lang.Thread.run(Unknown Source)

Something is mutating Jython's internal sys.modules map while we're attempting to iterate over it to "compile" the script transform.

I don't think it's anything you're doing wrong - likely a bug/race condition on our part.
I bet you won't be able to get it to happen in 8.3.

1 Like