[IGN-15393]Unable to save Vision Designer after writing to Dataset Tag

I’m attempting to store a custom list into a Vision Client Dataset tag. The following script seems to work, and I can see the data loaded into the tag:

myList = ['abc','def','foo']
headers = ['bar']
rows = [[x] for x in myList]   # one row per item
ds = system.dataset.toDataSet(headers, rows)
system.tag.writeBlocking('[client]myClientTag', ds)

However, when attempting to save, I get an error.

If I ‘touch’ the data in the client tag manually (e.g., double click on any value and edit it manually), I can save without issue.

Here's the entire error message com.inductiveautomation.ignition.common.xmlserialization.SerializationException: Error during serialization for property 'children' on object '[ClientTagFolder]com.inductiveautomation.factorypmi.application.sqltags.ClientTagFolder@130b72e2' at com.inductiveautomation.ignition.common.xmlserialization.serialization.DefaultObjectSerializationDelegate.serializeProperties(DefaultObjectSerializationDelegate.java:153) at com.inductiveautomation.ignition.common.xmlserialization.serialization.DefaultObjectSerializationDelegate.serialize(DefaultObjectSerializationDelegate.java:180) at com.inductiveautomation.ignition.common.xmlserialization.serialization.XMLSerializationContext.serialize(XMLSerializationContext.java:53) at com.inductiveautomation.ignition.common.xmlserialization.serialization.XMLSerializer.serialize(XMLSerializer.java:532) at com.inductiveautomation.ignition.common.xmlserialization.serialization.XMLSerializer.serializeBinary(XMLSerializer.java:513) at com.inductiveautomation.ignition.common.xmlserialization.serialization.XMLSerializer.serializeBinary(XMLSerializer.java:503) at com.inductiveautomation.factorypmi.designer.model.VisionDesignerImpl.serializeProjectResource(VisionDesignerImpl.java:1086) at com.inductiveautomation.factorypmi.designer.model.VisionDesignerImpl.syncAppToProject(VisionDesignerImpl.java:1160) at com.inductiveautomation.factorypmi.designer.model.VisionDesignerImpl.notifyProjectSaveStart(VisionDesignerImpl.java:651) at com.inductiveautomation.ignition.designer.IgnitionDesigner.lambda$getCommitTasks$46(IgnitionDesigner.java:1667) at com.inductiveautomation.ignition.designer.IgnitionDesigner.lambda$commitAll$41(IgnitionDesigner.java:1618) at java.base/java.util.stream.ReferencePipeline$3$1.accept(Unknown Source) at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(Unknown Source) at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source) at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(Unknown Source) at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source) at java.base/java.util.stream.ReferencePipeline.reduce(Unknown Source) at com.inductiveautomation.ignition.designer.IgnitionDesigner.commitAll(IgnitionDesigner.java:1626) at com.inductiveautomation.ignition.designer.IgnitionDesigner.handleSave(IgnitionDesigner.java:1377) at com.inductiveautomation.ignition.designer.IgnitionDesigner$Handler.lambda$handleSaveAction$12(IgnitionDesigner.java:2668) at com.inductiveautomation.ignition.client.util.gui.progress.Task$FunctionWrapper.apply(Task.java:247) at com.inductiveautomation.ignition.client.util.gui.progress.Task$FunctionWrapper.apply(Task.java:237) at com.inductiveautomation.ignition.client.util.gui.progress.Task.lambda$runInternal$3(Task.java:205) 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.ScheduledThreadPoolExecutor$ScheduledFutureTask.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 java.base/java.lang.Thread.run(Unknown Source) Caused by: com.inductiveautomation.ignition.common.xmlserialization.SerializationException: Unable to create clean copy of class com.inductiveautomation.ignition.common.script.builtin.PyDataset at com.inductiveautomation.ignition.common.xmlserialization.serialization.XMLSerializer.getCleanCopy(XMLSerializer.java:598) at com.inductiveautomation.ignition.common.xmlserialization.serialization.XMLSerializationContext.getCleanCopy(XMLSerializationContext.java:75) at com.inductiveautomation.ignition.common.xmlserialization.serialization.DefaultObjectSerializationDelegate.serializeProperties(DefaultObjectSerializationDelegate.java:143) at com.inductiveautomation.ignition.common.xmlserialization.serialization.DefaultObjectSerializationDelegate.serialize(DefaultObjectSerializationDelegate.java:180) at com.inductiveautomation.ignition.common.xmlserialization.serialization.XMLSerializationContext.serialize(XMLSerializationContext.java:53) at com.inductiveautomation.ignition.common.xmlserialization.serialization.DefaultObjectSerializationDelegate.writeConstructor(DefaultObjectSerializationDelegate.java:227) at com.inductiveautomation.ignition.common.xmlserialization.serialization.DefaultObjectSerializationDelegate.serializeConstructor(DefaultObjectSerializationDelegate.java:218) at com.inductiveautomation.ignition.common.xmlserialization.serialization.DefaultObjectSerializationDelegate.serialize(DefaultObjectSerializationDelegate.java:176) at com.inductiveautomation.ignition.common.xmlserialization.serialization.XMLSerializationContext.serialize(XMLSerializationContext.java:53) at com.inductiveautomation.ignition.common.xmlserialization.serialization.DefaultObjectSerializationDelegate.writeCall(DefaultObjectSerializationDelegate.java:90) at com.inductiveautomation.factorypmi.designer.xmlserialization.ProjectTagDelegate.serializeProperties(ProjectTagDelegate.java:39) at com.inductiveautomation.ignition.common.xmlserialization.serialization.DefaultObjectSerializationDelegate.serialize(DefaultObjectSerializationDelegate.java:180) at com.inductiveautomation.ignition.common.xmlserialization.serialization.XMLSerializationContext.serialize(XMLSerializationContext.java:53) at com.inductiveautomation.ignition.common.xmlserialization.serialization.delegates.ArrayListDelegate.serialize(ArrayListDelegate.java:23) at com.inductiveautomation.ignition.common.xmlserialization.serialization.delegates.ArrayListDelegate.serialize(ArrayListDelegate.java:17) at com.inductiveautomation.ignition.common.xmlserialization.serialization.XMLSerializationContext.serialize(XMLSerializationContext.java:53) at com.inductiveautomation.ignition.common.xmlserialization.serialization.DefaultObjectSerializationDelegate.writeCall(DefaultObjectSerializationDelegate.java:90) at com.inductiveautomation.ignition.common.xmlserialization.serialization.DefaultObjectSerializationDelegate.writeCall(DefaultObjectSerializationDelegate.java:77) at com.inductiveautomation.ignition.common.xmlserialization.serialization.DefaultObjectSerializationDelegate.doProperty(DefaultObjectSerializationDelegate.java:130) at com.inductiveautomation.ignition.common.xmlserialization.serialization.DefaultObjectSerializationDelegate.serializeProperties(DefaultObjectSerializationDelegate.java:151) ... 29 more

Ignition v8.3.2 (b2025120210)
Java: Azul Systems, Inc. 17.0.16

I think this is a known bug. I think it's been fixed, but not sure if for 8.3.4 or 8.3.5.

Known issue, not yet fixed.

The problem is this line; there's complicated internal reasons why, but this will work:

system.tag.writeBlocking('[client]myClientTag', [ds])

Absolute magic! Thank you for the workaround :slight_smile:

Just ran into this on 8.3.7

SerializationException: Error during serialization for property 'children' on object '[ClientTagFolder]
[...]
Unable to create clean copy of class com.inductiveautomation.ignition.common.script.builtin.PyDataset

My scripts are all written in this way: ...or at least I've been unable to find any that aren't

system.tag.writeBlocking(['[client]myClientTag'], [ds])

Do I need to remove the first set of brackets?

No, this is likely unrelated. Probably use of a column type that isn't whitelisted for use with tags.

The 'workaround' is to add the square brackets, to ensure that you go through the "list of values" codepath instead of the "it's a single object, maybe it's a list or maybe it isn't" codepath that broke on the update to PyDatasets in 8.3. That issue is fixed in 8.3.9.

I don't know of any other way that you'd end up in this scenario to deliver a PyDataset into a client tag in-memory that we'd then try to serialize than using the write functions, though it's possible there's some edge case with bidirectional bindings, maybe?