Informix Error -48
-48 Address already in use.
An operating-system error code with the meaning shown was unexpectedly returned to the database server. If the error recurs, note all circumstances and contact IBM Informix Technical Support.
Oninit® Troubleshooting Guidance
This is an operating-system error number, not an Informix diagnosis.
The same errno is returned by many different operations, so on its own it says what the operating system refused, not what Informix was trying to do. Informix will usually have reported a more specific error alongside it — in the message log, in the SQL or ISAM error pair, or in the accompanying assert failure — and that error normally defines the real cause far more precisely than the errno does. Find it before diagnosing from this number alone.
This matters less than it used to. Later versions of the engine trap many of these conditions and report them as specific Informix errors naming the operation, the object and the context, so a bare errno in this range is increasingly a sign of an older version, an unusual code path, or a failure early in startup before the better reporting is available. If you are seeing one on a current version, the more specific error is worth looking for even harder.
Important platform note. Error codes in this range represent operating-system
errnovalues whose meanings vary between Unix platforms and versions. Confirm the nativeerrnodefinition on the server where the Informix error occurred before diagnosing the problem from the number alone.
Determine the Native Error Meaning
The official text is correct about the condition and wrong about the number on every platform Informix runs on.
| Value | Symbol | |
|---|---|---|
| Catalogue text — Address already in use | 48 | EADDRINUSE on BSD |
| The same condition on Linux | 98 | EADDRINUSE |
| Errno 48 on Linux | 48 | ELNRNG — Link number out of range, STREAMS-era |
Codes -42 to -55 are the BSD socket block, and every one of them sits 50 higher on Linux. So a genuine "address already in use" on a Linux host carries errno 98. Errno 48 there is an unrelated STREAMS value that no database workload reaches.
python3 -c 'import os; print(48, os.strerror(48)); print(98, os.strerror(98))'
grep -wE '48|98' /usr/include/asm-generic/errno.h
Everything below concerns the condition — a listening address that cannot be claimed — regardless of which number your platform attaches to it.
What EADDRINUSE Actually Tells You
bind() was called on an address and port that something else already holds, or that the kernel still considers reserved.
Two distinct situations produce it, and they are fixed differently:
- Another process genuinely holds the port. A second instance, a leftover
oninit, or an unrelated service that took the port first. - Nothing holds it, but the kernel will not release it yet. A socket in
TIME_WAITfrom a previous incarnation keeps the address reserved for a protocol-mandated interval.
The second is the one that produces "but nothing is listening" — and it is the more common after a restart.
What This Means in Informix
The engine binds listening sockets for every network DBSERVERNAME and DBSERVERALIASES entry in sqlhosts. A bind that fails takes out the listener, so the instance may come up and still be unreachable — which presents to users as a connection failure rather than as a startup error.
Where it comes from:
- A previous instance has not fully exited. The most common cause by a wide margin, especially after a forced shutdown.
TIME_WAITafter a restart. Sockets from the previous run hold the address for the protocol interval.- Two instances configured on the same port. A copied
sqlhostswith the service or port left unchanged — the same family of fault as a duplicateSERVERNUMon -17, and it usually travels with it. - Another service took the port first, including an ephemeral outbound connection that happened to be assigned it.
- A port inside the ephemeral range, which makes that collision a matter of timing rather than configuration.
- Connection Manager or a proxy bound to an address the engine also wants.
- A DRDA listener and a SQLI listener configured on one port.
Common Causes
- A previous
oninitstill running, or exiting slowly. TIME_WAITsockets from the previous incarnation holding the address.- Duplicate ports across two instances'
sqlhostsentries. - A non-Informix service listening on the port.
- A configured port inside the ephemeral range, colliding intermittently with outbound connections.
- Two aliases in one
sqlhostsresolving to the same address and port. - A container publishing a port that the host also uses.
Diagnostic Checks
Find out whether anything actually holds the port, and what:
ss -lntp | grep -w <port>
ss -antp | grep -w <port> # includes TIME_WAIT and other states
lsof -nP -iTCP:<port>
netstat -lntp 2>/dev/null | grep -w <port>
ss -lntp empty while ss -antp shows TIME_WAIT entries is the "nothing is listening but I cannot bind" case.
Read the ports the instance expects:
cat "${INFORMIXSQLHOSTS:-$INFORMIXDIR/etc/sqlhosts}"
grep -nE 'DBSERVERNAME|DBSERVERALIASES' "$INFORMIXDIR/etc/$ONCONFIG"
Then resolve each service name, since sqlhosts may name a service rather than a number:
getent services <servicename>
grep -w <servicename> /etc/services
Check for a previous instance:
ps -ef | grep -E 'oninit' | grep -v grep
onstat -
ipcs -m | head
Check the ephemeral range, which decides whether a collision is configuration or chance:
sysctl net.ipv4.ip_local_port_range
A configured listener inside that range will collide sooner or later, and the failure will look random.
Compare across instances on the host:
for f in "$INFORMIXDIR"/etc/sqlhosts*; do echo "== $f"; grep -vE '^\s*#|^\s*$' "$f"; done
And confirm what the engine recorded:
tail -300 "$INFORMIXDIR/tmp/online.log"
onstat -g ntt
onstat -g ntu
Solutions / Resolution
- Establish which of the two situations you have — a live holder, or a reserved-but-idle address.
ss -lntpagainstss -antpseparates them immediately and the remedies share nothing. - If a previous instance still holds it, shut it down properly rather than starting a second one. Confirm it is really gone before retrying; see -17 for the shared-memory side of the same clean-up.
- If it is
TIME_WAIT, wait. The interval is protocol-mandated and short. This is the one case where retrying shortly is the correct response rather than a workaround. - Do not reach for
SO_REUSEADDRas a cure. Where it is configurable at all, it changes which conflicts are permitted rather than resolving them, and it can allow two listeners to coexist in ways that are much harder to diagnose than a clean refusal. - If two instances are configured on one port, that is the fault. Give each a distinct service entry and check
SERVERNUMand the chunk paths while you are in those files — a copied configuration rarely gets only one thing wrong. - Move a listener out of the ephemeral range if it sits inside it. An intermittent, unreproducible bind failure on a busy host is usually this.
- Re-check the listener after the instance starts, not just the instance. A bound-but-unreachable instance is the failure mode this error produces, and
onstat -alone will not reveal it.
Examples
Nothing is listening, and the port is still unavailable
$ ss -lntp | grep -w 9088
$
$ ss -antp | grep -w 9088 | head -3
TIME-WAIT 0 0 10.4.1.20:9088 10.4.1.51:52114
TIME-WAIT 0 0 10.4.1.20:9088 10.4.1.51:52118
TIME-WAIT 0 0 10.4.1.20:9088 10.4.1.51:52130
No listener, but the address is held by sockets from the previous run. The bind fails until the interval elapses. Waiting is the whole fix; forcing it is not.
Two instances, one service
$ grep -vE '^\s*#|^\s*$' "$INFORMIXDIR"/etc/sqlhosts.prod
ol_prod onsoctcp dbhost sqlexec_prod
$ grep -vE '^\s*#|^\s*$' "$INFORMIXDIR"/etc/sqlhosts.test
ol_test onsoctcp dbhost sqlexec_prod
$ getent services sqlexec_prod
sqlexec_prod 9088/tcp
sqlhosts.test was copied and the service entry was never changed. Whichever instance starts second loses its listener. The fix is a distinct service for the test instance — and a check of SERVERNUM and chunk paths in the same pass.
Platform Note
| Platform | This condition | Errno 48 there means |
|---|---|---|
| Linux | errno 98 | ELNRNG — STREAMS-era, unrelated |
| Solaris, AIX, HP-UX | confirm on the host | confirm on the host |
| BSD, Darwin | errno 48 | this condition |
The catalogue's number is the BSD one throughout this block. Confirm the local value before quoting a number into a ticket, because 48 and 98 mean entirely different things on the same Linux host.
The inspection tools differ as well:
| Task | Linux | Solaris | AIX |
|---|---|---|---|
| Listening sockets | ss -lntp |
netstat -an, pfiles |
netstat -Aan |
| Who holds a port | lsof -nP -iTCP:<port> |
pfiles across PIDs |
rmsock |
| Ephemeral range | sysctl net.ipv4.ip_local_port_range |
ndd /dev/tcp tcp_smallest_anon_port |
no -a | grep ephemeral |
On AIX, rmsock is the standard way to identify the process holding a socket and has no direct Linux equivalent.
Related Errors / Related Topics
- -49 — Can't assign requested address. The neighbouring bind failure, and the one to check next: there the address is not in use, it is not available on this host at all.
- -17 — File exists. The shared-memory face of the same copied-configuration problem. A duplicate port and a duplicate
SERVERNUMusually arrive together. - -32 — Broken pipe. The other end going away mid-stream, and the most common network error in practice.
Where a bind fails, check whether the instance came up anyway. An instance that is running with no listener is reachable only locally, and the users reporting it will describe a connection problem rather than a startup one.