However, one set has a listener created and the other doesn't.
Well that doesn't help you application stay available! You can absolutely have an availability group without a listener, but the useful of such setups are low.
(From Comments) The listener is the correct approach, but it's real function is to be able to direct intent read only connections to the proper secondary.
That's not quite correct. The listener always points to the primary replica and the main purpose of it is to facilitate transparent failover so that the connection strings do not need to change. One additional use is in read only routing as you've said but the primary use is actually for transparent failover.
(From Comments) ... but the Cluster Name provides the same seamless redirection to the primary node as the listener does.
The CNO has no idea about what an availability group is, which should be primary, etc. The CNO absolutely DOES NOT always point to the primary replica. You can connect using it only when the core cluster resources (which holds the CNO) happens to be owned by the same node as the AG primary but if it isn't - and the CNO doesn't follow the AG around - then it'll fail. Here's an example:
The one that doesn't have a listener is working fine. The one with the listener has issues at failover.
The one without the listener might be working fine... does it still work fine on a failover? Are they using some other DNS alias to "act" like the listener may.
The one with the listener, what does their connection string look like? If it isn't using the listener name in the connection string then of course it isn't going to work... they need to point it to the right place, that's why the listener exists!
The connection to the listener may also fail if there are multiple subnets, older client libraries are used, or certain keywords aren't in the connection string. If there are multiple subnets, the client driver should be something that supports the MultiSubnetFailover keyword and this should be set to TRUE.
It doesn't use the listener to connect, instead it uses the cluster name.
Well, that's 50% of the problem.
The GIS application accessing this server cannot connect to it after a failover.
If they update their connection string to use the listener and set MultiSubnetFailover = True then I'm betting it'll work... assuming the client library used to connect supports it.
I tried to have them use the listener but they said they couldn't even connect to that. I assume the listener hasn't been set up correctly.
If SQL Server created the listener for you, I highly doubt it is setup incorrectly... I won't rule out edge cases though.
Can I just remove the listener since it is not used anyways?
I would do the opposite. Have the GIS team change their connection string to the listener and set multisubnetfailover. It should, then, work... again with previously said assumptions.
But everything I read says that you need to use a listener, yet the servers without a listener are working fine. I'm so confused.
Yes, you do want to use the listener. The fact that it is working is either because there is some document that says "always have this on node3" or you've been getting lucky that it stays working. They might have used the replica name directly in the connection string also... that would allow it to connect. Depending on the settings for the secondary role it may or may not still connect and work properly... just depends on said settings.