# Inconsistent "timeout" exceptions for system.util.sendRequest

**URL:** <https://forum.inductiveautomation.com/t/inconsistent-timeout-exceptions-for-system-util-sendrequest/88026>\
**Category:** Ignition\
**Tags:** ignition81, perspective\
**Created:** [March 28, 2024, 10:06am UTC](https://forum.inductiveautomation.com/t/inconsistent-timeout-exceptions-for-system-util-sendrequest/88026 "2024-03-28T10:06:25Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![VinceV](https://avatars.discourse-cdn.com/v4/letter/v/bb73d2/32.png) [@VinceV](https://forum.inductiveautomation.com/u/VinceV)\
**Post date:** [March 28, 2024, 10:06am UTC](https://forum.inductiveautomation.com/t/inconsistent-timeout-exceptions-for-system-util-sendrequest/88026/1 "2024-03-28T10:06:25Z")

</div>

Hi,

Not sure if this is a bug or not: when a request to a remote gateway times out, the exceptions that are raised are inconsistent.

Most of the time a `com.inductiveautomation.metro.api.ex.TimeoutExpiredException` is thrown

```txt
Java Exception: <type 'com.inductiveautomation.metro.api.ex.TimeoutExpiredException'>
TimeoutExpiredException[queueId=scriptMsgQueue, targetIntent=PLATFORM_SCRIPT_REQ, msgData=com.inductiveautomation.ignition.gateway.clientcomm.scriptmsg.RemoteScriptMsg@7146e0f]

```

but occasionally a `java.util.concurrent.TimeoutException` is thrown instead, using the exact same request.

```txt
Java Exception: <type 'java.util.concurrent.TimeoutException'>
java.util.concurrent.TimeoutException: Timeout has expired for sendRequest operation

```

This makes it quite annoying to consistently and unambiguously catch a timeout exception (which is normally a transient error).

My test setup consists of a bare perspective view, containing only a TextArea and a OneShotButton. The `onActionPerformed` code for the button is below.

> **Code**
>
> ```py
> out = self.getSibling("TextArea")
> out.props.text = "Busy ..."
> 	
> import java.lang.Throwable
> 	
> _remoteServer = "OT01"
> _project = "Redacted"
> _messageHandler = "Product"
> _timeoutSec = 2
> 	
> payload = {"action": "getById", "id": '784a4eca-1383-41b1-affb-b862356ed269'}
> 	
> try:
> response = system.util.sendRequest(_project, _messageHandler, payload, _remoteServer, _timeoutSec)
> out.props.text = repr(response)
> except java.lang.Throwable as t:
> out.props.text = "Java Exception: {}\n{}".format(t.getClass(), repr(t))
> except Exception as e:
> out.props.text = "Python Error: {}\n{}".format(e. __name__ , repr(e))
> finally:
> self.props.value = 0
> 
> ```

We're running Ignition 8.1.36 on Windows Server 2019. The "OT01" gateway connection is configured in the settings, but is disabled to simulate this error.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [March 28, 2024, 3:38pm UTC](https://forum.inductiveautomation.com/t/inconsistent-timeout-exceptions-for-system-util-sendrequest/88026/2 "2024-03-28T15:38:39Z")

</div>

A Metro timeout indicates the request over the gateway network failed.  
A "plain" timeout means the request to the local gateway the designer/client is connected to failed.

The request always has to go through the local gateway before it can reach the remote, so two different timeouts. But you should be able to catch both within a single exception block using the tuple syntax?

---

<div class="post-metadata">

**Author:** ![VinceV](https://avatars.discourse-cdn.com/v4/letter/v/bb73d2/32.png) [@VinceV](https://forum.inductiveautomation.com/u/VinceV)\
**Post date:** [March 29, 2024, 7:22am UTC](https://forum.inductiveautomation.com/t/inconsistent-timeout-exceptions-for-system-util-sendrequest/88026/3 "2024-03-29T07:22:24Z")

</div>

Ah, makes sense, and good to know that there is this distinction.

My current solution is indeed to wrap the sendRequest call in a separate function, catching these two exceptions there and re-raising them as a custom Python error.
