OPC UA connection error NullPointerException

Hello everyone,

I’ve tried to connect to a machine’s PLC with Ignition via OPC UA.
The PLC allows anonymous connection thus i do not have a user or password .

I already connected to the PLC using UA Expert without any problems.
When i try to connect via Ignition from the same server i get a FAULTED connection with this additional text:

java.lang.NullPointerException: Cannot invoke "String.hashCode()" because "<local1>" is null
at org.eclipse.milo.opcua.stack.core.transport.TransportProfile.fromUri(TransportProfile.java:26)
at org.eclipse.milo.opcua.stack.client.UaStackClient.create(UaStackClient.java:389)
at org.eclipse.milo.opcua.sdk.client.OpcUaClient.create(OpcUaClient.java:158)
at com.inductiveautomation.ignition.gateway.opcua.client.ManagedClientKt.createClient(ManagedClient.kt:220)
at com.inductiveautomation.ignition.gateway.opcua.client.ManagedClientKt.initialize(ManagedClient.kt:141)
at com.inductiveautomation.ignition.gateway.opcua.client.ManagedClientKt.access$initialize(ManagedClient.kt:1)
at com.inductiveautomation.ignition.gateway.opcua.client.ManagedClientKt$initialize$1.invokeSuspend(ManagedClient.kt)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
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)

8.1.36 (b2024010211)
Azul Systems, Inc. 17.0.8

In the Logs i have the following messages

2025-11-07 11:36:56:361 webserver-5106140
Error looking up endpoint
java.util.concurrent.ExecutionException: java.net.UnknownHostException: No such host is known (SIMATIC)
at java.base/java.util.concurrent.CompletableFuture.reportGet(Unknown Source)
at java.base/java.util.concurrent.CompletableFuture.get(Unknown Source)
at com.inductiveautomation.ignition.gateway.opcua.client.connection.web.discovery.wizardsteps.ChooseDiscoveryServerStep.getEndpoints(ChooseDiscoveryServerStep.java:116)
at com.inductiveautomation.ignition.gateway.opcua.client.connection.web.discovery.wizardsteps.ChooseDiscoveryServerStep.next(ChooseDiscoveryServerStep.java:103)
at org.apache.wicket.extensions.wizard.dynamic.DynamicWizardModel.next(DynamicWizardModel.java:126)
at com.inductiveautomation.ignition.gateway.opcua.client.connection.web.discovery.EndpointWizardButtonBar$NextButton.onClick(EndpointWizardButtonBar.java:26)
at org.apache.wicket.extensions.wizard.WizardButton.onSubmit(WizardButton.java:88)
at org.apache.wicket.markup.html.form.Form.delegateSubmit(Form.java:1304)
at org.apache.wicket.markup.html.form.Form.process(Form.java:967)
at org.apache.wicket.markup.html.form.Form.onFormSubmitted(Form.java:789)
at org.apache.wicket.markup.html.form.Form.onFormSubmitted(Form.java:701)
at jdk.internal.reflect.GeneratedMethodAccessor131.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at org.apache.wicket.RequestListenerInterface.internalInvoke(RequestListenerInterface.java:258)
at org.apache.wicket.RequestListenerInterface.invoke(RequestListenerInterface.java:216)
at org.apache.wicket.core.request.handler.ListenerInterfaceRequestHandler.invokeListener(ListenerInterfaceRequestHandler.java:243)
at org.apache.wicket.core.request.handler.ListenerInterfaceRequestHandler.respond(ListenerInterfaceRequestHandler.java:236)
at org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor.respond(RequestCycle.java:890)
at org.apache.wicket.request.RequestHandlerStack.execute(RequestHandlerStack.java:64)
at org.apache.wicket.request.cycle.RequestCycle.execute(RequestCycle.java:261)
at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:218)
at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:289)
at org.apache.wicket.protocol.http.WicketFilter.processRequestCycle(WicketFilter.java:259)
at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:201)
at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:282)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:210)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1635)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:527)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:131)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:578)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:223)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1570)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:221)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1384)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:176)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:484)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1543)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:174)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1306)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:129)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122)
at com.inductiveautomation.catapult.handlers.RemoteHostNameLookupHandler.handle(RemoteHostNameLookupHandler.java:121)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122)
at org.eclipse.jetty.rewrite.handler.RewriteHandler.handle(RewriteHandler.java:301)
at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:51)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122)
at org.eclipse.jetty.server.Server.handle(Server.java:563)
at org.eclipse.jetty.server.HttpChannel.lambda$handle$0(HttpChannel.java:505)
at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:762)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:497)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:282)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:314)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:100)
at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:558)
at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:379)
at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:146)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:100)
at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:416)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:385)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:272)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.lambda$new$0(AdaptiveExecutionStrategy.java:140)
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:411)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:969)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1194)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1149)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.net.UnknownHostException: No such host is known (SIMATIC)
at java.base/java.net.Inet6AddressImpl.lookupAllHostAddr(Native Method)
at java.base/java.net.InetAddress$PlatformNameService.lookupAllHostAddr(Unknown Source)
at java.base/java.net.InetAddress.getAddressesFromNameService(Unknown Source)
at java.base/java.net.InetAddress$NameServiceAddresses.get(Unknown Source)
at java.base/java.net.InetAddress.getAllByName0(Unknown Source)
at java.base/java.net.InetAddress.getAllByName(Unknown Source)
at java.base/java.net.InetAddress.getAllByName(Unknown Source)
at java.base/java.net.InetAddress.getByName(Unknown Source)
at io.netty.util.internal.SocketUtils$8.run(SocketUtils.java:156)
at io.netty.util.internal.SocketUtils$8.run(SocketUtils.java:153)
at java.base/java.security.AccessController.doPrivileged(Unknown Source)
at io.netty.util.internal.SocketUtils.addressByName(SocketUtils.java:153)
at io.netty.resolver.DefaultNameResolver.doResolve(DefaultNameResolver.java:41)
at io.netty.resolver.SimpleNameResolver.resolve(SimpleNameResolver.java:61)
at io.netty.resolver.SimpleNameResolver.resolve(SimpleNameResolver.java:53)
at io.netty.resolver.InetSocketAddressResolver.doResolve(InetSocketAddressResolver.java:55)
at io.netty.resolver.InetSocketAddressResolver.doResolve(InetSocketAddressResolver.java:31)
at io.netty.resolver.AbstractAddressResolver.resolve(AbstractAddressResolver.java:106)
at io.netty.bootstrap.Bootstrap.doResolveAndConnect0(Bootstrap.java:220)
at io.netty.bootstrap.Bootstrap.access$000(Bootstrap.java:46)
at io.netty.bootstrap.Bootstrap$1.operationComplete(Bootstrap.java:189)
at io.netty.bootstrap.Bootstrap$1.operationComplete(Bootstrap.java:175)
at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:590)
at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:557)
at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:492)
at io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:636)
at io.netty.util.concurrent.DefaultPromise.setSuccess0(DefaultPromise.java:625)
at io.netty.util.concurrent.DefaultPromise.trySuccess(DefaultPromise.java:105)
at io.netty.channel.DefaultChannelPromise.trySuccess(DefaultChannelPromise.java:84)
at io.netty.channel.AbstractChannel$AbstractUnsafe.safeSetSuccess(AbstractChannel.java:990)
at io.netty.channel.AbstractChannel$AbstractUnsafe.register0(AbstractChannel.java:516)
at io.netty.channel.AbstractChannel$AbstractUnsafe.access$200(AbstractChannel.java:429)
at io.netty.channel.AbstractChannel$AbstractUnsafe$1.run(AbstractChannel.java:486)
at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:174)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:167)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:569)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
... 1 common frames omitted

2025-11-07 11:37:02:191 webserver-5106141
Unable to reach host: SIMATIC at port: 4845

2025-11-07 11:37:34:429 webserver-5103958
Certificate has not been trusted. Connection to OPC server may not work properly.

I have already trusted the certificate and set a hostname override with the correct IP address.
I have also delete the certificate from the trust store and readded it and also deactivated the certificate validation in the connection properties.

Had someone already this problem and has a solution?

Ignition 8.1.36
Thanks for your help in advance and Best Regards,
Gerald

Is this happening during the discovery wizard? What is the exactly discovery / endpoint URL you are entering?

During the discovery wizard everything works as usual. The wizard shows the server and asks for alternative discovery URL, endpoint and hostname override, always with prefilled IP address.

i tried opc.tcp://10.XXX.YYY.12:4845 and opc.tcp://10.XXX.YYY.12:4845/discovery. Both got the same result.

Click that "skip to advanced configuration" link at the top right and show me what you see there.

Both blurred IPs are the same

This all looks right, there must be a field coming back in the EndpointDescription that is null and probably shouldn't be, and we're not looking for it or expecting it, and just passing that value on into the SDK.

Can you get a Wireshark capture that includes you doing an edit/save on the connection to force a reconnect?

Here is the wireshark dump.
Starting with the wizard and afterwards a few reconnects.

Thanks, as I expected/feared, the transport profile URI in the returned endpoints is null:

I don't think there's a workaround, this is broken behavior by the server that I'm going to have to modify Ignition to support.

Oh no… Is this a miss-configuration on the PLCs side or standard behaviour?

Do you have any rough timeline or estimate for when a fix might be available? This will help us plan accordingly on our end.

My experience has been that the SimaticNET OPC server has a very poor implementation of OPC UA compared to the one on the S7 PLCs. You might see if there's a software update available.

Not sure on timeline. New issues get prioritized for 8.3, then optionally back-ported to 8.1 if serious enough. Since there's no workaround here this probably qualifies.