What is a 999 error and how can I troubleshoot it? It's not an error code that IIS will allow a custom error page for.


Yup, you are correct in saying that error 999 is not an HTTP Error that IIS will generate. Hence, you cannot configure a custom error page for it.

Therefore, your question is really: "what arbitrary code is running on my server for some given request that generates this unexpected response", and I can only say that "it is arbitrary custom code that can do whatever it want for whatever reason... so I have no idea WHY it is sending a 999 error".

I can only help you determine the list of possible custom ISAPI DLLs that are running for this request. IIS gives no information on which ISAPI DLL(s) generated which part of the response, but it should be easy to determine through process of elimination. The possible custom ISAPI DLLs that run on a given request are configured at:

  1. Global Filters
  2. Site Filters
  3. Applicable ScriptMap for the given URL

Script Tools for Static Analysis

The following script tools allow you to enumerate and examine every ISAPI DLL listed at those locations:

  • FiltTool.js - Add/Remove/Enumerate ISAPI Filters at the global and site level
  • ChgList.vbs - Enumerate/Modify LIST datatype (like ScriptMap) for a given URL

For example, suppose the request that triggers the 999 response is to http://foo/bar/baz.ext, http://foo is site ID 1, and /bar is a virtual directory or application. Then you simply do the following:

  1. CSCRIPT FiltTool.js -site:W3SVC
    Enumerate all global ISAPI Filters applicable for the request
  2. CSCRIPT FiltTool.js -site:W3SVC/1
    Enumerate all site ID 1's ISAPI Filters
  3. CSCRIPT ChgList.vbs W3SVC/1/ROOT/bar/ScriptMaps foobar *
    Retrieve the effective value of ScriptMaps for /bar (which contains /baz.ext)
  4. CSCRIPT %SYSTEMDRIVE%\Inetpub\AdminScripts\ADSUtil.vbs GET W3SVC/1/ROOT/bar/baz.ext/ScriptMaps
    If it exists, retrieve the ScriptMaps value from the IIsWebFile of /baz.ext. It is ok for this to fail.

The FiltTool.js commands show the global and site filters applicable to the request.

The effective ScriptMap for the URL is #4 if it succeeds; if #4 fails, then the effective ScriptMap is #3. Once you know the effective ScriptMap, you should determine if any Script Engines are processing the * extension and whether a Script Engine is processing the .ext extension.

Runtime Behavior

Of course, the static analysis only shows the POSSIBLE ISAPI Filters and ISAPI Extensions that can execute on the request, and in the ideal case, it is what happens. However, realize that at runtime, any of the ISAPI DLLs can alter/rewrite the request to change actual execution, and there is NO easy way to determine these changes through static analysis of configuration.

You basically have to attach a debugger and set breakpoints on the necessary ISAPI Filter and ISAPI Extension APIs to determine if alteration/rewrite happens. On IIS6 in Windows Server SP1 you can turn on ETW tracing and ISAPI tracing to get a similar spew of information to dig through... but basically, without extensive knowledge of IIS and debugging, you cannot figure out real runtime behavior.

Good Luck.