Layer 5 · Session

The Phantom Limb

The connection was there. I could prove it. Every Oracle tool on the box confirmed it — TNSPING came back clean, SQLPLUS connected without hesitation, Net8 Assistant showed green lights across the board. The database was alive. The network path was open. The credentials were valid. From Oracle's perspective, there was no problem.

IIS disagreed.

Microsoft OLE DB Provider for ODBC Drivers error '80004005' [Microsoft][ODBC driver for Oracle][Oracle]

That was it. That was the whole error. No explanation, no detail, no suggestion. Just a refusal. The ODBC driver would not establish a session with a database that every other tool on the same machine could reach without difficulty. Two programs, same server, same credentials, same network path — one connects, one doesn't. The door was open and the ODBC driver was standing in front of it insisting the building didn't exist.

This was my first week.


They'd hired me as a contractor at a global technology company — the kind of operation that has offices on three continents and a server room that hums at a frequency you can feel in your back teeth. My first assignment was supposed to be a routine migration: move IIS services from an old Windows 2000 Server to a new one. Same OS, same version, same patches. Identical twins. The ASP pages talked to a remote Oracle database through a DSN-less ODBC connection, and the whole thing had been running fine on the old box for years.

On the new box, it wouldn't connect. The local admin had already been working the problem before I arrived. No luck. The ticket landed on my desk with a shrug and a prayer.


I did what you do when the obvious answers have already been tried: I stopped looking at the application and started looking at everything else.

I spent days checking every component between the two servers. IIS configuration. ASP connection strings. ODBC driver versions. Oracle client settings. Network routes. Permissions. Service accounts. Everything matched. Everything was identical. The two servers were mirrors of each other in every respect except one.

The registry.

On the old server, the Oracle configuration was clean. One HOME entry — HOME0 — pointing to the client installation, with every default reference aimed at the same place. A single room in a single hallway, door open, lights on.

The new server had six.

HOME0. HOME1. HOME2. HOME3. HOME4. HOME5. Six Oracle HOME entries stacked in the registry like headstones in a graveyard. Most of them pointing to paths that no longer existed, configurations from installations that had been removed but never fully cleaned up. And the working configuration — the one that TNSPING and SQLPLUS were happily using, the one where the connection actually lived — was sitting at HOME5. The last door at the end of a hallway full of ghosts.

The Microsoft ODBC driver doesn't walk hallways. It walks up to HOME0 and if nobody answers, it leaves. Always HOME0. Regardless of which home entry is active, regardless of which one the Oracle tools are using, regardless of which one actually has the working configuration. First door. Only door. The session was there. The database was waiting. The driver was knocking on an empty room while the answers sat five doors down in a hallway it didn't know existed.


Every job has a Jimmy. The mistake is thinking that tells you what kind.

This Jimmy was the local admin. Solid guy. Knew the environment, knew the servers, knew where the cables went and which service accounts had which permissions. When the ODBC connection failed on the new server, Jimmy did exactly what you'd do: he reinstalled the Oracle client. When that didn't work, he reinstalled it again. And again. And again.

Six times.

Each install followed the same pattern. Run the installer. Configure the client. Test with Oracle's tools — connection works. Test with IIS — connection fails. Assume the install was bad. Uninstall. Try again. Each time, the installer laid down a new HOME entry. Each uninstall removed most of the files but left the registry entry behind. And each fresh install picked the next number in the sequence, stacking its working configuration one layer deeper in a registry that was accumulating phantom limbs from every previous attempt.

Jimmy wasn't careless. Jimmy wasn't lazy. Jimmy was methodical. He just didn't know that the driver had a secret it didn't advertise. The more Jimmy tried, the deeper the answer was buried. The graveyard was built out of diligence, not negligence.


I cleaned the registry by hand. Deleted HOME0, HOME1, HOME2, HOME3, HOME4. Renamed HOME5 to HOME0. Updated every reference — the ORACLE_HOME key, the ALL_HOMES counter, the DEFAULT_HOME pointer. Carefully. One entry at a time. Making the new server's registry look exactly like the old server's, with the working configuration sitting where the ODBC driver expected to find it.

The ASP pages connected on the first try.


Case closed. For five days.

On day six, the error came back. Same message, same refusal, same door-that-leads-nowhere. Except now it was worse — even Oracle's own tools had stopped connecting. TNSPING failed. SQLPLUS failed. The database hadn't moved. The network hadn't changed. The registry was exactly where I'd left it. And nothing worked.

ORA-12538. TNS: no such protocol adapter.

I stared at it for a while. Checked the registry. Clean. Checked the Oracle configuration files. Clean. Checked the network. Fine. Everything was exactly right, and nothing worked, and the error message was telling me the protocol adapter didn't exist, which was like being told the telephone hadn't been invented yet by someone who was speaking to you on the telephone.

On a lark — and I want to be clear about this, because the narrative of the competent detective demands that every solution be the product of methodical reasoning, and this one wasn't — on a lark, I added a system environment variable. SET ORACLE_HOME = c:\oracle\ora81. A value that was already in the registry. A value that every Oracle tool already knew about. A value that shouldn't have mattered at all.

It worked.

Why did the registry fix work the first time? Why did it stop working five days later? Why did an environment variable that duplicated information already present in the registry fix it again? I don't know. I never found out. The system worked and I left it alone and I moved on to the next problem, because that's the other thing nobody teaches you about this job: not every case gets solved. Some cases just stop. The symptoms vanish, the system stabilizes, and you're left with a solution you can't fully explain and a nagging suspicion that you didn't actually fix anything — you just made the ghost comfortable enough to stop rattling the chains.


The ODBC driver stood in a hallway full of doors and knocked on the wrong one. Not because the wrong one was locked. Not because the right one was hidden. Because a well-meaning admin had filled the hallway with phantom rooms while trying to build the one that worked, and the driver was hardcoded to try the first door it saw and no other.

I cleaned the graveyard. The ghost came back anyway. I set an environment variable on a hunch and it went quiet.

Some cases you solve. Some cases you survive.

Case closed.