Setting link.toNode seems to be bugged since 2.3.11


we updated our project to use the latest GoJS release (v.2.3.11).
Now an error occurs when we try to set toNode on a link Node.
We do this after the diagramEvent LinkDrawn.
The link seems to be a valid Node and the Node we want to set on toNode is also a proper go.Node.
We did not change our code since we updated the GoJS version. When we go back to v.2.3.10, it works again without a problem.

The error in question:
After this line (link.toNode was null before)
link.toNode = newNode;

TypeError: f is not a function
    at T.set (go-module.js:1643:214)

gojs bug

Could you provide your whole LinkDrawn handler?

There doesn’t seem to be a problem here:

Have you set Link.toPortChanged?

Link.toPortChanged is not set.

Our LinkDrawn handler is split into multiple functions and throughout multiple files so I will write up a simplified pseudo variant.

diagram.addDiagramListener('LinkDrawn', (e: go.DiagramEvent)=> {
    const link = e.subject;
    const point = e.diagram.lastInput.documentPoint;

    if (link.fromNode && !link.toNode) {
         const newNode = diagram.findNodeForData(createNewNode(params))!;
         link.toNode = newNode;
         link.toPortId = newNode.ports.first()!.portId;

I’ve updated the sample above to be more like yours and there are still no issues with 2.3.11.

Based on the error location, it seems like your Link.toPortChanged value is non-null. Could you put a breakpoint in your LinkDrawn function to verify whether link.toPortChanged is null?

I did exactly that.

Link.toPortChanged is null

I gave the go-debug-module.js a try and stepped through it.
When going down the setter of link.toNode you eventually come here through setToNodeForLink.
In t.wa, a is the data of the new node. The data object is correct. The function then proceeds to return the key inside the data object.

The result of this function is apperently used to set the value of Link.toPortChanged (before that, it is null).
The error then happens here
Calling this can of course not work since it is a number.

Those function calls are expected. It’s looking up the new node’s key to set as the link data’s to key.

What’s unexpected (and we can’t reproduce) is that key being set as the Link.toPortChanged function.

What is “MappingModel”? Have you overridden GraphLinksModel? Or have you set GraphLinksModel.linkToKeyProperty to some function with side-effects?

Yes, we do override GraphLinksModel in order to ensure type safety with our own data model in the project.

We do not set GraphLinksModel.linkToKeyProperty manually anywhere.

export class MappingModel<MD extends MappingModelData> extends go.GraphLinksModel {
    constructor(nodeDataArray: go.ObjectData[], linkDataArray: go.ObjectData[], modelData: MD) {
        super(nodeDataArray, linkDataArray);

        this.modelData = modelData;

        this.makeUniqueKeyFunction = (model: go.Model) => ++modelData.maxId;

        let linkId = -1;
        this.makeUniqueLinkKeyFunction = (model: go.GraphLinksModel) => --linkId;

        this.linkKeyProperty = 'key';
        this.linkFromPortIdProperty = 'fromPort';
        this.linkToPortIdProperty = 'toPort';

Can you keep stepping in to figure out when toPortChanged is being set from null to the key? Also, just to be sure, you aren’t using any minified property names, correct?

Even with an extended model, things are working as expected: LinkDrawn - StackBlitz

Are you accidentally setting anywhere in your code? It would explain this

.to is the relevant minified symbol, and is not part of the API.

No we are not setting anywhere in our code.

We are also not using minified property names, only what is available in go.d.ts

I tried my best debugging this for an hour. There is a change being constructed on the data of the link that we set toNode on. But the change is about ‘to’.

I lost the trace here. My only guess left is that since something happens with promises/observables here, that something listens on changes and changes it retro-actively?
link.toPortChanged is null until this function was executed/stepped through 2-3 times.

I deleted all packages and caches multiple times. Now I only get this error with the release go-module.js but not with the go-debug-module.js. If that helps.

Is this live somewhere that we can look at it? We still can’t reproduce the issue.

If not, maybe you can try setting a conditional breakpoint in the toPortChanged setter for non-null values to get the stack trace.

This is really strange. We’re very interested in reproducing this.

Does this custom build work?

@jhardy No, our application is not accessible publicly.

Edit: Outdated
The breakpoint in the setter of toPortChanged is a good idea, sadly it doesn’t yield any result.
The setter is not being called, only the getter.


Edit: Outdated
The custom build did not yield any different result. Same as before
The setter is still not called or at least the debugger wont stop there. Not even when I edit the build manually, adding a debugger statement in the setter.

Edit: Actually, I translated the changes (renaming to to zzz) into the ES6 bundle file which our application uses. Then it worked, the error was gone! I still cant debug it really, but I can now see that toPortChanged stays null

It does suggest that somewhere in your code accidentally you are setting a .to on a go.Link, and in your code before 2.3.11 this was just attaching a new property to that link since .to does not exist, but now its causing the problem.

You might want to search for .to (case sensitive, whole word) in all your code just to review each case, just in case. I know that your link data (very reasonably) contains .to, and maybe somewhere its getting set on a Link instead of Link data.

If you are modifying model data objects, you should be calling some Model method, such as:

And all changes should happen within a transaction.

@simon I did check that 3 times already. We do not set (not even access)

@walter I will check our code for that and try it out if applicable.

I am very relieved to say that I found the issue.

I did search our entire codebase for “.to” and also just “to” again.
And I found this in our connection template. Hidden in plain daylight:

new go.Binding('from', 'from').makeTwoWay(),
new go.Binding('to', 'to').makeTwoWay(),

Deleting the to binding solved the issue. I removed the “from” binding as well, since, as you guys stated, these are internal properties which are set automatically by the framework.
No more “f is not a function error” and the application works like before! 💯

Thank you for your help and patience.

I’m glad the mystery is solved.