ClipboardPasted: Cannot read properties of null (reading 'iterator')

I have 3 templates of Node, which 1 of them has copyable: false (not sure if it makes sense). When I paste nodes & links from clipboard, I have an error:
Uncaught TypeError: Cannot read properties of null (reading 'iterator')

Digging into this error, I found some variable, which has not been redefined from null for some reason. In turn, c.Kj function lead to some PartManager’s function.

Piece of Node template:

    $create(
      Go.Node,
      'Auto',
      {
        deletable: modelType !== 'modules',
        copyable: modelType !== 'modules',
        opacity: 1,
        defaultAlignment: Go.Spot.Center,
        selectionAdornmentTemplate: makeBorderSelected(STYLES),
        selectionChanged(model: any) {
          const initialOpacity = 1

          if (model.isSelected) {
            if (import.meta.env.MODE !== 'production') {
              console.info('SELECTED MODEL:', { ...model.part.findTopLevelPart().data })
            }

            model.layerName = 'Foreground'
            model.opacity = initialOpacity
          } else {
            model.layerName = ''
          }
        },
      },

      new Go.Binding('deletable', 'user_defined'),
      new Go.Binding('location', 'position', Go.Point.parse).makeTwoWay(Go.Point.stringify),

     more code goes here...
   )

Example of Node’s model:

{
  TEMP_TEMPLATE: "modules_model", // nodeCategoryProperty

  id: "a893138e-46c8-47a2-a531-780a94cea74b", // nodeKeyProperty
  description: "Description of 'status'",
  is_virtual: false,
  module_model_id: 48,
  name: "status",
  position: "483 252",
  user_defined: false,
  version: 14,
  fields: [{
    id: "1b9ce492-2ce1-4cb2-b618-c92a226f6bde"
    avt: 0
    description: "Description of 'id'"
    dv: null
    ei: null
    generated: true
    hidden: false
    index: false
    json_name: "id"
    module_id: null
    name: "id"
    not_null: true
    order: "0"
    rmi: null
    unique: true
    vt: 1
  }],
  indexes: [{
    fields: (3) ['c31a1296-4108-4812-9ba9-31a91c59b9fc']
    id: "R9MNTimQfV6R9ogheMNS"
    name: "my_index"
    type: 1
  }]
}

That error breakes my ClipboardPasted callback function which is critical.

Which version of GoJS are you using?

I’m using 2.3.10

Yes, it does seem like our code isn’t checking for null there. But I don’t know how you got into that situation. In my quick test of copy-pasting nodes and links where some of the nodes are not copyable, I was unable to reproduce any problem. But I can try again with the code and data that you provided.

What is this?

fields: (3) [‘c31a1296-4108-4812-9ba9-31a91c59b9fc’]

That’s not valid JavaScript or JSON. It doesn’t look like debugger output either.

What had the user copied (into the clipboard) before the paste command?

I also think copyable doesnt make sense.

The diagram initializes with 3 mock nodes, which 1 of them copyable: false (orange one), and 1 link between 2 random nodes. I select them by Ctrl + A and immidiately do Ctrl + V, then I get this:

I still can interact with diagram properly.

Why do you say “I also think copyable doesn’t make sense.” I don’t understand the statement.

What is this?

fields: (3) [‘c31a1296-4108-4812-9ba9-31a91c59b9fc’]

That’s not valid JavaScript or JSON. It doesn’t look like debugger output either. I’d like to know what the value of “fields” actually is, and whether it shares any references with anything, especially with the data.fields Array or any Object in it

Have you customized the CommandHandler at all?

This is chrome devtool output of data.indexes.fields. I copied that json from console, which contains 3 strings in array, but I left one string and forgot to remove “(3)”.

data.fields array is itemArray binding for TableRow panel inside Table. On the screenshot above you can see 1-4 Tables between gray dividers, inside them these data.fields are rendering.

Yes, I did customizations of CommandHandler:

diagram.commandHandler.copySelection = function () {
      const appStore = useAppStore()
      const hasModelInSelection = diagram.selection.any((part: Go.Part) => part instanceof Go.Node)

      if (hasModelInSelection && appStore.modelsReachedLimit) return

      Go.CommandHandler.prototype.copySelection.call(this)
    }

I have checked behavior without this overriding, the error occurs anyway. But what i just noticed is the error doesn’t occur when I try to copy without mock-generated Link:


Then I select the Link and copyable: false Node:

Mock-generated Link looks like:

$create(
      Go.Link,
      {
        routing: Go.Link.Normal,
        curve: Go.Link.Bezier,
        fromEndSegmentLength: 60,
        toEndSegmentLength: 60,
        smoothness: 1,
        layerName: 'Background',
        contextMenu: makeContextMenu('relation-menu'),

        selectionAdornmentTemplate: $create(
          Go.Adornment,
          {},

          ...makeLinkShape(STYLES, { state: 'active' }),
        ),

        mouseEnter(e, link: any) {
          link.elt(0).stroke = STYLES.COLOR
        },
        mouseLeave(e, link: any) {
          link.elt(0).stroke = 'transparent'
        },
      },

      ...
    )
{
  id: "f64c65c1-10c6-4c78-ac1c-c2296b7f6f3c", // linkKeyProperty
  from_model_id: "ddcbb1ed-0abb-4970-86cb-22b825a0facd", // linkFromKeyProperty
  to_model_id: "3c68f9f6-7c41-4d46-9d9c-9d1ad33e7649", // linkToKeyProperty
  from_field_id: "a3d5e926-6274-4498-bef5-2fc086eca0b3", // linkFromPortIdProperty
  to_field_id: "c70aa3a4-5e17-4e2c-bb4e-a11810403d27", // linkToPortIdProperty
  protected: false,
  type: 1,
}

It seems the error occurs because of my logic with extra fields for relation. I did filtration of these relation fields after pasting from clipboard and the error has gone:


P.S. If I select Link as well and do copy-paste, Link will be connected between the models, not the ports, and I won’t get the error.