Setting HTTP Request Timeouts in Titanium SDK the Reliable Way
Titanium SDK's HTTPClient has no built-in retry and platform-dependent timeout errors. Set the timeout property explicitly, implement capped retries yourself, and verify on both platforms.
30 Jul 2025, 12:30 UTC

The problem: requests that hang longer than your users will wait
If you build a Titanium SDK app that talks to an API, sooner or later a request will stall — a slow server, a dead cell connection, a captive portal. Without an explicit timeout, your UI sits in a loading state with no obvious failure, and the only signal you get is the onerror callback firing whenever the underlying platform stack gives up. The fix is simple: set the timeout property on Ti.Network.HTTPClient and handle the error callback deliberately. The subtlety is that timeout behavior and error reporting differ between iOS and Android, so a handler written and tested on one platform can silently misbehave on the other.
What the HTTPClient actually gives you
Ti.Network.createHTTPClient() accepts a timeout property, expressed in milliseconds. When the request exceeds that duration, the client aborts and invokes your onerror callback. Inside that callback you receive an event object with error (a message string) and code (a numeric status). The exact message text and code values come from the native networking stack — URLSession on iOS, the Android HTTP stack on Android — so they are not identical across platforms. Do not write logic that string-matches an iOS error message and assume it will work on Android.
A few things Titanium's HTTPClient does not give you out of the box, despite what various snippets floating around suggest:
- No built-in automatic retry or backoff policy. If you need retries, you implement them yourself around
send(). - No cross-platform timeout error constant. You detect a timeout by inspecting the error event, and the safest cross-platform signal is often simply that
onerrorfired after roughly your configured timeout elapsed. - No guaranteed single default timeout worth relying on. Treat the default as unspecified for your purposes and always set
timeoutexplicitly.
A worked example with explicit timeout and manual retry
This pattern sets a 5-second timeout, logs the outcome, and implements a simple bounded retry with a growing delay. Run it in any Titanium controller or service module; no special permissions are needed beyond normal network access (Android requires the INTERNET permission, which Titanium templates include by default).
function fetchWithRetry(url, maxAttempts, done) {
var attempt = 0;
function tryOnce() {
attempt++;
var client = Ti.Network.createHTTPClient({
timeout: 5000, // milliseconds
onload: function () {
Ti.API.info('HTTP ' + this.status + ' from ' + url);
done(null, this.responseText);
},
onerror: function (e) {
Ti.API.warn('Attempt ' + attempt + ' failed: code=' + e.code + ' error=' + e.error);
if (attempt < maxAttempts) {
var delay = 1000 * attempt; // linear backoff; keep it simple
setTimeout(tryOnce, delay);
} else {
done(e);
}
}
});
client.open('GET', url);
client.send();
}
tryOnce();
}
fetchWithRetry('https://example.com/api/status', 3, function (err, body) {
if (err) {
Ti.API.error('Request ultimately failed');
return;
}
Ti.API.info('Got response: ' + body.length + ' bytes');
});
Two deliberate choices here: the retry count is capped so a dead server cannot loop forever, and each attempt creates a fresh HTTPClient, since reusing a finished client instance is a common source of confusing state bugs.
How to verify the timeout actually fires
Do not trust the configuration — observe it. Point the request at an endpoint you control that sleeps longer than your timeout (a one-line test server, or a public delay endpoint), then:
- Run on the iOS simulator and the Android emulator separately.
- Watch the console (or filter Titanium CLI logs) for your
onerrorlog line. Confirm it appears at roughly the configured timeout, not much earlier or later. - Record the
e.codeande.errorvalues on each platform and write your production error handling against what you actually observe, not against assumptions. - Test on a real device on a weak cellular connection; emulators on fast desktop networks rarely exercise real timeout paths.
Trade-offs and limitations
A short timeout improves perceived responsiveness but increases false failures on slow networks; a long one does the opposite. There is no universally right value — pick one tied to your API's expected latency and your UX tolerance, and make it configurable if you can. Also note that timeout covers the whole request lifecycle as the platform stack interprets it, and backgrounding the app can change networking behavior on both platforms in ways that vary by OS version. If your app must complete requests while backgrounded, test that scenario explicitly rather than assuming the foreground behavior carries over.
Actionable takeaway: set timeout explicitly on every HTTPClient, log e.code and e.error per platform, implement retries yourself with a hard cap, and verify against a deliberately slow endpoint on both iOS and Android before shipping.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.