Windows 11 26H2 (26300.9818): GetTcpTable2 returns state 0 for a verified listening socket

Pask Pask 0 Reputation points
2026-11-04T18:05:29.1+00:00

Windows_TCP_SyntheticResult.txtWindows 11 26H2 build 26300.9818: native IPv4 TCP tables report state 0 for a demonstrably listening synthetic socket

Summary

I observed an inconsistency between a socket owned by a small standalone Python program and the state returned for that socket by Windows IP Helper APIs. The program binds an exclusive IPv4 loopback socket to port 0, calls listen(), reads SO_ACCEPTCONN=1, accepts a client, and successfully exchanges two fixed, fictional byte strings. Nevertheless, GetTcpTable, GetTcpTable2, and GetExtendedTcpTable with TCP_TABLE_OWNER_PID_LISTENER report state 0, rather than 2, for its listening endpoint. The corresponding connected endpoints report 5.

This report is based on retained observations from 4 November 2026. Preparing this report did not run the reproducer again or change Windows. KB5127936 was installed, but I have not performed a local before/after removal experiment. I cannot establish that this update is the exclusive cause.

Recorded environment

| Item | Retained value |

| --- | --- |

| Windows version/build | Windows 11 26H2, 26300.9818 |

| Update present | KB5127936; installation date reported as 2026-10-28 |

| Environment collection record | 2026-11-04T16:52:41.4771265Z |

| iphlpapi.dll file version | 10.0.26100.9949 |

| tcpip.sys file version | 10.0.26100.8875 |

| netio.sys file version | 10.0.26100.9818 |

| afd.sys file version | 10.0.26100.9949 |

| Reproducer dependencies | Python standard library only: socket, ctypes, struct, JSON and filesystem support |

The fixture output did not record the exact Python version, architecture, Windows edition or elevation level. A separate validation-environment record from the same session reports Python 3.12.10, 64-bit AMD64; it is not a direct measurement of the fixture interpreter. Different networking file versions alone do not establish an incomplete update or damaged system files. The build and update information comes from the retained environment records, not from a new inspection during report preparation.

Microsoft's release note identifies KB5127936 as a preview update for this build. This establishes the release association, not causation of this symptom.

Minimal standalone reproduction already executed

The attached minimal-repro/fixture_native_probe.py is byte-identical to the retained source used for the synthetic observation. It does not import the affected application, launch an inference engine, read model files, inspect application configuration, or send HTTP requests.

Historical sequence:

  1. Create an IPv4 TCP socket and set SO_EXCLUSIVEADDRUSE.
  2. Bind to 127.0.0.1:0, obtaining an OS-selected ephemeral port; call listen(1).
  3. Read SO_ACCEPTCONN; capture the four table variants listed below.
  4. Connect a client to that exact endpoint and accept it in the same process.
  5. Exchange fictional-witness and fictional-ack; capture the tables again while the listening socket remains open.
  6. Close all three sockets; verify their descriptors are closed and capture the tables once more.

The APIs are called sequentially, not atomically. GetExtendedTcpTable uses AF_INET=2, bOrder=FALSE, Reserved=0, and classes 3/4. The decoder uses 32-bit unsigned fields, a 4-byte table header, and row sizes of 20/28/24 bytes for GetTcpTable/GetTcpTable2/owner-PID rows. It converts the low 16 port bits from network byte order. No state value is remapped.

The source asserts size-query return code 122 and final data-call return code 0. It permits at most three buffer-allocation attempts if the required size changes. The retained JSON records final codes, not allocation-attempt counts. This is Python/ctypes evidence, not a locally compiled Windows SDK witness. Review of the declarations does not independently rule out every possible decoder issue. See GetTcpTable, GetTcpTable2, and GetExtendedTcpTable.

Actual synthetic result

Run-start timestamp: 2026-11-04T16:53:29.120209+00:00. Fixture PID: 39428. Listener: 127.0.0.1:6226. Client: 127.0.0.1:6227. These are historical, test-only identifiers, not ports to reuse. There are no per-call timestamps.

| API / class | Before client connection: listening endpoint | During connection: listening endpoint | During connection: connected endpoints |

| --- | --- | --- | --- |

| GetTcpTable | state 0; no PID field | state 0 | both state 5; no PID field |

| GetTcpTable2 | state 0, PID 39428 | state 0, PID 39428 | both state 5, PID 39428 |

| GetExtendedTcpTable / OWNER_PID_LISTENER (3) | state 0, PID 39428 | state 0, PID 39428 | not in this table |

| GetExtendedTcpTable / OWNER_PID_CONNECTIONS (4) | empty | not in this table | both state 5, PID 39428 |

All 12 final data retrievals returned 0, including the four calls after closure. SO_ACCEPTCONN was 1 and the byte exchange succeeded. After closure, the LISTENER table was empty for the test port. Other sequential calls retained a closing row with state 1/PID 0 or state 11/PID 0; that residual closing-row observation is not presented as another defect or a leaked listener.

Expected interpretation: LISTEN=2, ESTABLISHED=5, and FIN_WAIT_1=6 describe different TCP states. I do not interpret 0 as LISTEN, CLOSED, or proof of ownership. The independent listening evidence here is the program's own socket, SO_ACCEPTCONN, and successful acceptance—not the table class name alone. State definitions; SO_ACCEPTCONN.

Separate historical observations, not part of this reproducer

An earlier synthetic HTTP fixture returned HTTP 200 while CIM reported state 6 for its zero-peer endpoint and psutil labelled it FIN_WAIT1. That record lacks a TCP-sampling timestamp; its process creation time was 2026-11-04T14:49:52.553360+00:00. These interfaces may share underlying Windows facilities; their agreement is not independent kernel-level confirmation.

Two pre-existing application endpoints also produced state 0/6 zero-peer rows in native tables. A separate later health check returned HTTP 200 from both services. The package contains only selected, pseudonymized rows from that historical observation: no application names, process command lines, real service ports, executable paths or instance identifiers. It must not be conflated with the isolated fixture, or used to claim exclusive listener ownership from HTTP health. Differences among successive connected-row samples are reported as observations, not proof of a particular internal race.

What is established, and what is not

Measured: the controlled listener remained open across the before/during phases, accepted a connection, and exchanged fixed bytes; all three API families returned state 0 for its listening row in the recorded run. No application-specific lifecycle code participates in this reproduction.

Inference: the immediate mismatch is reproducible outside the affected applications and outside their PowerShell parsers. It warrants investigation of the native enumeration path. The APIs may share underlying implementation, so this is not three independent proofs of a kernel defect.

Not established: the responsible layer, whether this is a regression introduced by KB5127936, whether it affects every machine on this build, or whether a driver, interception layer or decoder issue contributes. I have not performed a controlled update-removal comparison, a clean-install comparison, an IPv6 test, a trace of kernel state, or an independent compiled SDK reproduction on this machine. No third-party security driver from another person's report is attributed to this machine. This is one retained standalone run, not a measured failure rate.

A similar Microsoft Q&A report and an Ollama issue provide comparison cases. They are reports by their authors, not my measurements. I have not identified an official Microsoft confirmation of this specific regression or an official fix in the referenced release information. I am not claiming that Microsoft has confirmed it.

Questions for MicrosoftWindows_TCP_SyntheticResult.txt

  1. Is state 0 expected under any documented condition for a socket that is demonstrably listening? If so, which contract should callers use?
  2. Is this pattern already tracked for build 26300.9818, and is there a supported fix or diagnostic procedure?
  3. Which narrowly scoped trace would distinguish an enumeration/translation problem from the actual TCP endpoint state, without collecting unrelated traffic or disabling security controls?

The application currently refuses process-control decisions when ownership cannot be verified; this report does not propose treating state 0/6 as LISTEN.

Attachments and verification

observations.md describes the chronology, provenance and redactions. evidence/synthetic-observation.json is an exact copy of the retained synthetic output. The public package includes sanitized environment and contextual observations, a privacy review, and SHA-256 manifests. Original private records remain unchanged and are not attached. Checksums support byte verification; they do not independently authenticate the host or prove root cause.

The reproducer README explains manual use and limitations. The public copy was not rerun when preparing this report. No Windows update was removed, no reboot or system repair performed, and no application process controlled during this documentary task.

Attachments and reproduction files

Windows_TCP_MinimalRepro_Instructions.txt

Windows_TCP_MinimalRepro_Source.txt

Windows_TCP_Observations.txt

Windows_TCP_Report_EN.txt

Windows_TCP_SyntheticResult.txt

Windows development | Windows API - Win32

1 answer

Sort by: Newest
  1. Harry Nguyen (WICLOUD CORPORATION) 525 Reputation points Microsoft External Staff Moderator
    2026-11-05T06:31:33.32+00:00

    Hi @Pask Pask , 

    Thank you for the detailed and carefully scoped report. Separating what you measured from what you inferred makes this much easier to review. Below is my answer to each question. 

    1. Is state 0 expected under any documented condition? 

    dwState is documented to take one of the MIB_TCP_STATE values, from MIB_TCP_STATE_CLOSED (1) to MIB_TCP_STATE_DELETE_TCB (12), as described in MIB_TCPROW2 and MIB_TCPROW_OWNER_PID. The current documentation doesn't define any meaning for 0. So your decision not to interpret 0 (or 6) as LISTEN, and not to use it for process-control decisions, matches the documented contract. 

    As an interim signal, your own data may help. According to TCP_TABLE_CLASS, TCP_TABLE_OWNER_PID_LISTENER returns listening TCP endpoints. In your run, the row for the test port appeared in that table with the expected PID while the socket was open, and was gone after closure. Please treat this as an observation from your run, not a guaranteed contract. It's still more useful than relying on dwState alone while this behavior is being looked at. 

    2. Is this pattern already tracked? 

    This behavior has been noted, and similar reports have been seen on the same build. I'm not able to share further details at this point. I'd recommend keeping an eye on the Windows 11, version 26H2 known issues and notifications page and re-checking your reproducer after upcoming cumulative updates. If possible, please also submit the repro through Feedback Hub (Network and Internet category) so the data reaches the right team through the official channel. 

    3. Which narrowly scoped trace would help? 

    Your reproducer already shows that the socket is listening, accepts a connection, and exchanges data. Packet-level tools such as Packet Monitor (Pktmon) mainly help with packet flow and drops, so they're unlikely to add much here. The most useful step, which is also scoped and doesn't touch unrelated traffic or security controls, is a controlled comparison: 

    Run the same fixture_native_probe.py on the same machine before and after an update change. For example, after the next cumulative update, or on a test machine with and without KB5127936. 

    In the same window, record netstat -ano -p tcp and Get-NetTCPConnection -LocalPort <port> for the test port only. That gives a cross-tool view of the same moment. 

    This keeps the data narrow and comparable, and it's exactly the kind of evidence that's helpful to attach to a Feedback Hub report. 

    I hope this helps. If anything changes after your next update, please feel free to share the result here. 

    If you found this helpful, you can refer to this guidance to confirm it and help others with similar questions. 

    Thank you. 

    Was this answer helpful?

    1 person found this answer helpful.

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.